Skip to content
Latchkey

Git "detached HEAD" state in CI

CI checkouts deliberately check out the exact commit SHA, not a branch, so HEAD is detached. That is fine for building, but steps that need a branch name or want to push will fail or push nowhere useful.

What this error means

Git reports HEAD detached at <sha>. git rev-parse --abbrev-ref HEAD returns HEAD, branch-name scripts return empty, and a push fails or goes to a dangling ref.

git
Note: switching to '9fceb02'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches.

Common causes

CI checks out a commit, not a branch

actions/checkout and most CI runners check out the triggering SHA so builds are reproducible, which leaves HEAD detached.

A script assumes a current branch

Tooling that reads the branch from git rev-parse --abbrev-ref HEAD gets HEAD and either errors or uses the wrong value.

A push from detached HEAD has no upstream

Without a local branch tracking a remote ref, the push has no obvious destination.

How to fix it

Read the branch from CI metadata

  1. Use the CI-provided branch variable instead of parsing git HEAD.
  2. On Actions use github.ref_name or GITHUB_HEAD_REF for pull requests.
.github/workflows/ci.yml
BRANCH="${GITHUB_HEAD_REF:-${GITHUB_REF_NAME}}"
echo "Building branch: $BRANCH"

Create a local branch before pushing

  1. Check out a named branch at the current SHA when a step must commit or push.
  2. Set the upstream explicitly on push.
Terminal
git checkout -B "$BRANCH"
git push origin "HEAD:$BRANCH"

How to prevent it

  • Never derive the branch from git HEAD in CI; read the runner-provided ref variable, and create a named branch before any commit-and-push step.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →