Summary
Repository.push rejects HEAD:<destination> when the repository is in a detached-HEAD state, although command-line Git accepts this refspec and pushes the current commit.
MissionControl encountered this while implementing requested changes directly on the exact detached head of an existing pull request.
Reproduction
let repo = try Repository.open(at: worktree)
try repo.checkout(ref: headSHA) // detached HEAD
try repo.push(
remote: "origin",
refspec: "HEAD:refs/heads/feature/review-fixes",
setUpstream: false)
Actual result
libgit2 error (-1/4): src refspec HEAD does not match any
qualifiedPushRefspec treats every unqualified source as a local branch or tag. Because detached HEAD is neither, it rejects the refspec before libgit2 can push it.
Expected result
Match Git's behavior for:
git push origin HEAD:refs/heads/feature/review-fixes
The current detached HEAD commit should be pushed to the destination branch. A normal push must retain fast-forward protection.
Current workaround in MissionControl
MissionControl now creates a uniquely named temporary local branch at the detached HEAD, pushes that fully qualified ref to the PR's source branch, restores the detached checkout, and deletes the temporary branch. For fork-based PRs it also adds and removes a temporary authenticated remote.
Supporting HEAD directly in GitKit would remove that extra branch lifecycle and improve command-line Git parity.
Summary
Repository.pushrejectsHEAD:<destination>when the repository is in a detached-HEAD state, although command-line Git accepts this refspec and pushes the current commit.MissionControl encountered this while implementing requested changes directly on the exact detached head of an existing pull request.
Reproduction
Actual result
qualifiedPushRefspectreats every unqualified source as a local branch or tag. Because detachedHEADis neither, it rejects the refspec before libgit2 can push it.Expected result
Match Git's behavior for:
The current detached HEAD commit should be pushed to the destination branch. A normal push must retain fast-forward protection.
Current workaround in MissionControl
MissionControl now creates a uniquely named temporary local branch at the detached HEAD, pushes that fully qualified ref to the PR's source branch, restores the detached checkout, and deletes the temporary branch. For fork-based PRs it also adds and removes a temporary authenticated remote.
Supporting
HEADdirectly in GitKit would remove that extra branch lifecycle and improve command-line Git parity.