Severity
Low. Cosmetic but user-visible: the work item shows the correct title, so it looks fine until someone clicks the link and lands on a 404. Only affects commit messages using the GH-1234 reference form; the far more common #1234 and owner/repo#1234 forms are unaffected. No data corruption, no workaround needed beyond using a different reference syntax.
Found while investigating #10176 (Azure DevOps work item tracking); unrelated to that issue's cause, filed separately so it doesn't widen the decision being made there.
Version
Verified on main as of 2026-08-18, in GitHubWorkItemLinkMapper.NormalizeLinkData. Present since the GitHub issue tracker was introduced — the GH- reference form has always been accepted by the comment parser and has never been handled by the link builder.
Latest Version
I could reproduce the problem in the latest build
What happened?
A commit message of the form Fixes GH-1234 is recognised by the GitHub issue tracker's comment parser, which produces IssueNumber = "1234" and LinkData = "GH-1234". The work item's description resolves correctly — GetGitHubOwnerAndRepo falls back to the owner/repo of the commit's own repository and Octokit fetches issue 1234 from it, giving the real issue title.
But NormalizeLinkData builds a nonsensical URL. Because "GH-1234" contains no #, Split('#') yields a single component ["GH-1234"], which is non-empty, so the method takes the "we have org/repo formatted" branch:
var linkDataComponents = linkData.Split('#').ToList();
if (!string.IsNullOrEmpty(linkDataComponents[0]))
{
// we have org/repo or user/repo formatted, insert "issues" between that and the issueId
linkDataComponents.Insert(1, "issues");
// switch to the baseUrl, rather than calc relative to the vscRoot
baseToUse = baseUrl;
}
"GH-1234" is treated as if it were an owner/repo segment, issues is appended after it, and the base switches from the VCS root to the configured base URL. The result is:
Note that the issue number is absent from the URL entirely — 1234 was never a separate component to begin with, so it is silently dropped rather than merely misplaced. With the default base URL this yields https://github.com/GH-1234/issues, which is not a valid GitHub path.
Expected: the same URL the equivalent bare reference produces. Fixes #1234 correctly yields <vcsRoot>/issues/1234, and GH-1234 is just an alternative spelling of the same same-repo reference, so it should resolve identically — relative to the VCS root, not the base URL.
Reproduction
- Enable the GitHub issue tracker in Configuration ➜ Settings.
- Commit to a GitHub-hosted repo with the message
Fixes GH-1234, where 1234 is a real issue in that repo.
- Push build information to Octopus and create a release.
- The work item shows the correct issue title, but its link points at
https://github.com/GH-1234/issues instead of <repo>/issues/1234.
More Information
The fix is confined to NormalizeLinkData in source/Octopus.Core/Features/IssueTrackers/GitHub/WorkItems/GitHubWorkItemLinkMapper.cs — strip a leading GH- (case-insensitive, as the parser matches case-insensitively) and treat the remainder as a bare same-repo issue id, i.e. take the same path as the else branch that handles #1234.
Two things to be careful of:
baseToUse must stay as the VCS root for this form, not switch to the base URL. The switch to baseUrl only makes sense for genuine owner/repo#id references, where the target repo differs from the one being built.
- No existing test asserts the broken URL, so nothing needs updating to accommodate the fix. The only current
GH- coverage is CommentParserScenarios, which asserts parser output (LinkData == "GH-1234") and is correct as-is. A NormalizeLinkData test for this form should be added alongside the existing link-building tests in source/Octopus.Core.UnitTests/Features/IssueTrackers/GitHub/WorkItemLinkMapperScenarios.cs.
Worth confirming as a product question while fixing: whether GH- should keep being accepted at all. It is a GitHub-supported shorthand, so presumably yes, but it is rare enough in practice that it has gone unnoticed since the integration shipped.
Workaround
Use #1234 or owner/repo#1234 in commit messages instead of GH-1234.
Severity
Low. Cosmetic but user-visible: the work item shows the correct title, so it looks fine until someone clicks the link and lands on a 404. Only affects commit messages using the
GH-1234reference form; the far more common#1234andowner/repo#1234forms are unaffected. No data corruption, no workaround needed beyond using a different reference syntax.Found while investigating #10176 (Azure DevOps work item tracking); unrelated to that issue's cause, filed separately so it doesn't widen the decision being made there.
Version
Verified on
mainas of 2026-08-18, inGitHubWorkItemLinkMapper.NormalizeLinkData. Present since the GitHub issue tracker was introduced — theGH-reference form has always been accepted by the comment parser and has never been handled by the link builder.Latest Version
I could reproduce the problem in the latest build
What happened?
A commit message of the form
Fixes GH-1234is recognised by the GitHub issue tracker's comment parser, which producesIssueNumber = "1234"andLinkData = "GH-1234". The work item's description resolves correctly —GetGitHubOwnerAndRepofalls back to the owner/repo of the commit's own repository and Octokit fetches issue 1234 from it, giving the real issue title.But
NormalizeLinkDatabuilds a nonsensical URL. Because"GH-1234"contains no#,Split('#')yields a single component["GH-1234"], which is non-empty, so the method takes the "we have org/repo formatted" branch:"GH-1234"is treated as if it were anowner/reposegment,issuesis appended after it, and the base switches from the VCS root to the configured base URL. The result is:Note that the issue number is absent from the URL entirely —
1234was never a separate component to begin with, so it is silently dropped rather than merely misplaced. With the default base URL this yieldshttps://github.com/GH-1234/issues, which is not a valid GitHub path.Expected: the same URL the equivalent bare reference produces.
Fixes #1234correctly yields<vcsRoot>/issues/1234, andGH-1234is just an alternative spelling of the same same-repo reference, so it should resolve identically — relative to the VCS root, not the base URL.Reproduction
Fixes GH-1234, where 1234 is a real issue in that repo.https://github.com/GH-1234/issuesinstead of<repo>/issues/1234.More Information
The fix is confined to
NormalizeLinkDatainsource/Octopus.Core/Features/IssueTrackers/GitHub/WorkItems/GitHubWorkItemLinkMapper.cs— strip a leadingGH-(case-insensitive, as the parser matches case-insensitively) and treat the remainder as a bare same-repo issue id, i.e. take the same path as theelsebranch that handles#1234.Two things to be careful of:
baseToUsemust stay as the VCS root for this form, not switch to the base URL. The switch tobaseUrlonly makes sense for genuineowner/repo#idreferences, where the target repo differs from the one being built.GH-coverage isCommentParserScenarios, which asserts parser output (LinkData == "GH-1234") and is correct as-is. ANormalizeLinkDatatest for this form should be added alongside the existing link-building tests insource/Octopus.Core.UnitTests/Features/IssueTrackers/GitHub/WorkItemLinkMapperScenarios.cs.Worth confirming as a product question while fixing: whether
GH-should keep being accepted at all. It is a GitHub-supported shorthand, so presumably yes, but it is rare enough in practice that it has gone unnoticed since the integration shipped.Workaround
Use
#1234orowner/repo#1234in commit messages instead ofGH-1234.