feat: add raw diff/patch endpoint for repository comparisons (#37632)

## Summary

Adds `GET
/repos/{owner}/{repo}/compare/{basehead}.{diffType:diff|patch}`,
mirroring the existing `/git/commits/{sha}.{diffType}` endpoint but for
comparisons between two arbitrary refs.

The new endpoint streams a raw unified diff or `git format-patch` output
between any two refs:

GET /repos/{owner}/{repo}/compare/main...feature.diff
GET /repos/{owner}/{repo}/compare/v1.0..v1.1.patch
GET /repos/{owner}/{repo}/compare/abc1234...def5678.diff

Resolves #5561, #13416 and #17165.

AI was used while creating this PR. Automated tests were added as per
the contribution policy.

---------

Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Rafail Giavrimis
2026-06-15 17:37:15 +01:00
committed by GitHub
parent b4cb192fba
commit 052feee34a
8 changed files with 275 additions and 11 deletions
+6 -3
View File
@@ -1269,9 +1269,12 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) {
m.Get("/commit/*", context.RepoRefByType(git.RefTypeCommit), repo.TreeViewNodes)
})
m.Get("/compare", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff)
m.Combo("/compare/*", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists).
Get(repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff).
Post(reqSignIn, context.RepoMustNotBeArchived(), reqUnitPullsReader, repo.MustAllowPulls, web.Bind(forms.CreateIssueForm{}), repo.SetWhitespaceBehavior, repo.CompareAndPullRequestPost)
m.PathGroup("/compare/*", func(g *web.RouterPathGroup) {
g.MatchPath("GET", "/<basehead:*>.diff", repo.MustBeNotEmpty, repo.DownloadCompareDiff)
g.MatchPath("GET", "/<basehead:*>.patch", repo.MustBeNotEmpty, repo.DownloadComparePatch)
g.MatchPath("GET", "/<*:*>", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff)
g.MatchPath("POST", "/<*:*>", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists, reqSignIn, context.RepoMustNotBeArchived(), reqUnitPullsReader, repo.MustAllowPulls, web.Bind(forms.CreateIssueForm{}), repo.SetWhitespaceBehavior, repo.CompareAndPullRequestPost)
})
m.Get("/pulls/new/*", repo.PullsNewRedirect)
}, optSignIn, context.RepoAssignment, reqUnitCodeReader)
// end "/{username}/{reponame}": repo code: find, compare, list