Skip to content

Push should accept detached HEAD as a source refspec #29

Description

@odrobnik

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions