RemoteContainsCommit cannot verify detached HEAD commits via git ls-remote #35

Open
opened 2026-05-04 22:00:34 +02:00 by heiko · 0 comments
Owner

Problem

RemoteContainsCommit uses git ls-remote to check whether the current HEAD commit exists on the remote. git ls-remote only lists ref tips (branch heads and tags) — it cannot confirm that an arbitrary commit SHA is reachable from any remote ref.

This means the check silently passes (returns true) for detached HEAD commits that are not the tip of any remote branch or tag. This is the correct pragmatic behaviour for CI pipelines (where detached HEAD almost always means the commit came from the remote), but it means the safety net is absent for that case.

Affected scenario

A -- B -- C  ← origin/main
              \
               D  ← HEAD detached, no tag, no remote branch tip

If HEAD is at D and D is not a remote branch/tag tip, RemoteContainsCommit returns true without actually verifying D exists on the remote.

Prior approach

The original git branch -r --contains <SHA> would have caught ancestors of remote branches, but it fails entirely in shallow clones (no local remote-tracking refs), which is the common CI case.

Possible fix

For the detached HEAD + no matching ref case, attempt git fetch --depth=1 <remote> <sha> as a last resort. If the server supports uploadpack.allowReachableSHA1InWant (enabled by default on Forgejo/Gitea), this would confirm the commit is reachable. If it fails, reject.

This needs to be weighed against the side effects of a fetch operation and the assumption about server configuration.

## Problem `RemoteContainsCommit` uses `git ls-remote` to check whether the current HEAD commit exists on the remote. `git ls-remote` only lists **ref tips** (branch heads and tags) — it cannot confirm that an arbitrary commit SHA is reachable from any remote ref. This means the check silently passes (returns `true`) for detached HEAD commits that are **not** the tip of any remote branch or tag. This is the correct pragmatic behaviour for CI pipelines (where detached HEAD almost always means the commit came from the remote), but it means the safety net is absent for that case. ## Affected scenario ``` A -- B -- C ← origin/main \ D ← HEAD detached, no tag, no remote branch tip ``` If HEAD is at D and D is not a remote branch/tag tip, `RemoteContainsCommit` returns `true` without actually verifying D exists on the remote. ## Prior approach The original `git branch -r --contains <SHA>` would have caught ancestors of remote branches, but it fails entirely in shallow clones (no local remote-tracking refs), which is the common CI case. ## Possible fix For the detached HEAD + no matching ref case, attempt `git fetch --depth=1 <remote> <sha>` as a last resort. If the server supports `uploadpack.allowReachableSHA1InWant` (enabled by default on Forgejo/Gitea), this would confirm the commit is reachable. If it fails, reject. This needs to be weighed against the side effects of a fetch operation and the assumption about server configuration.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
heiko/gogogo#35
No description provided.