Description
Gitea’s GET /api/v1/repos/{owner}/{repo}/git/refs/{ref} endpoint currently returns a JSON array even when the request targets a single, specific reference such as heads/main. This differs from GitHub’s REST API behavior and breaks clients that expect a single ref object for exact references
Reproduction
- Ensure repository has a branch
main (so the ref is refs/heads/main).
- Call:
GET /api/v1/repos/{owner}/{repo}/git/refs/heads/main
Actual behavior
Response is an array with a single element:
[
{
"ref": "refs/heads/main",
"url": "...",
"object": { "type": "commit", "sha": "...", "url": "..." }
}
]
This leads to deserialization failures in some GitHub API clients expecting an object for an exact ref.
Expected behavior (GitHub-compatible)
For an exact ref request like heads/main, the response should be a single reference object (not an array). Arrays should be reserved for prefix/filtered requests that match multiple refs.
Root cause in current code
In routers/api/v1/repo/git_ref.go, Gitea returns an object only when the filter matches the ref name exactly:
|
// If single reference is found and it matches filter exactly return it as object |
|
if len(apiRefs) == 1 && apiRefs[0].Ref == filter { |
|
ctx.JSON(http.StatusOK, &apiRefs[0]) |
|
return |
|
} |
However, for a request like /git/refs/heads/main, filter is heads/main, while the ref name is refs/heads/main. Therefore this condition never matches for the GitHub-style path, and Gitea returns an array even for a single match.
Suggested fix
Normalize the filter before comparison (or relax the comparison) so that heads/main is treated as an exact match for refs/heads/main. For example, when len(apiRefs) == 1, consider returning an object when:
apiRefs[0].Ref == filter, or
apiRefs[0].Ref == "refs/" + filter
This would preserve the current “prefix search returns list” behavior, but restore GitHub-compatible behavior for exact refs like heads/{branch}.
Description
Gitea’s
GET /api/v1/repos/{owner}/{repo}/git/refs/{ref}endpoint currently returns a JSON array even when the request targets a single, specific reference such asheads/main. This differs from GitHub’s REST API behavior and breaks clients that expect a single ref object for exact referencesReproduction
main(so the ref isrefs/heads/main).GET /api/v1/repos/{owner}/{repo}/git/refs/heads/mainActual behavior
Response is an array with a single element:
[ { "ref": "refs/heads/main", "url": "...", "object": { "type": "commit", "sha": "...", "url": "..." } } ]This leads to deserialization failures in some GitHub API clients expecting an object for an exact ref.
Expected behavior (GitHub-compatible)
For an exact ref request like
heads/main, the response should be a single reference object (not an array). Arrays should be reserved for prefix/filtered requests that match multiple refs.Root cause in current code
In
routers/api/v1/repo/git_ref.go, Gitea returns an object only when the filter matches the ref name exactly:gitea/routers/api/v1/repo/git_ref.go
Lines 102 to 106 in e589126
However, for a request like
/git/refs/heads/main,filterisheads/main, while the ref name isrefs/heads/main. Therefore this condition never matches for the GitHub-style path, and Gitea returns an array even for a single match.Suggested fix
Normalize the filter before comparison (or relax the comparison) so that
heads/mainis treated as an exact match forrefs/heads/main. For example, whenlen(apiRefs) == 1, consider returning an object when:apiRefs[0].Ref == filter, orapiRefs[0].Ref == "refs/" + filterThis would preserve the current “prefix search returns list” behavior, but restore GitHub-compatible behavior for exact refs like
heads/{branch}.