Git “You are in ‘detached HEAD’ state”: what it means and how to get out safely

Normally HEAD points at a branch, and the branch points at a commit. “Detached” means HEAD points straight at a commit, with no branch name in between. Nothing is broken, but new commits have no name holding on to them.

What git is telling you

$ git checkout v2.1.0
Note: switching to 'v2.1.0'.

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 by switching back to a branch.

HEAD is git’s “you are here” marker. On a branch, .git/HEAD contains ref: refs/heads/main; when you commit, the branch moves forward and HEAD follows it. When detached, .git/HEAD contains a bare commit hash (a SHA-1 like those the hash generator makes). Commits still work, but when you switch away, no branch remembers them.

How you ended up here

You ranWhy it detaches
git checkout a1b2c3dA commit hash is not a branch
git checkout v2.1.0Tags are fixed labels; they never move, so you can’t be “on” one
git checkout origin/mainRemote-tracking branches are read-only copies of the server’s state
A rebase that stopped on a conflictGit replays commits detached, then re-attaches when the rebase finishes
git submodule updateSubmodules are checked out at the exact commit the parent repo recorded
CI (GitHub Actions, GitLab, Jenkins)Pipelines check out the exact commit being tested, so git branch shows (HEAD detached at …)

Just looking? Go back to a branch

git switch main        # or: git checkout main
git switch -           # back to wherever you were before

If you only looked around or ran tests, that’s all. Any files you edited but didn’t commit come with you, unless they clash; then git refuses and you can git stash first.

Made commits? Keep them before you leave

git switch -c my-fix   # new branch right here; your commits now have a name
git switch main
git merge my-fix       # or open a pull request from my-fix

Want them on an existing branch instead? Note the hashes with git log --oneline, switch to the branch and git cherry-pick <hash> each one.

Already switched away and the commits “vanished”?

They aren’t gone yet. Git keeps unreferenced commits for at least about two weeks (often 30 days or more) before garbage collection. Git usually even prints a warning with the hash as you leave. Otherwise ask the reflog, git’s diary of where HEAD has been:

git reflog
# 3f9e2a1 HEAD@{0}: checkout: moving from 7c41d0b to main
# 7c41d0b HEAD@{1}: commit: fix the parser
git branch rescued 7c41d0b

Compare what you rescued with git diff main rescued, or paste two versions into the text diff tool.

In CI or a submodule

Check where HEAD points

git status                    # "HEAD detached at v2.1.0" or "On branch main"
git symbolic-ref -q HEAD      # prints refs/heads/main, or fails when detached
git branch --show-current     # empty output = detached

Pushes being rejected after you rescue your work? See git push rejected (non-fast-forward).

error: src refspec main does not match any on push usually means the branch name does not exist locally yet: src refspec main does not match any.

Questions

Is detached HEAD bad?

No. It is a normal state for looking at old versions, tags and CI builds. The only risk is making commits and then switching away without creating a branch, which leaves those commits without a name.

How do I fix detached HEAD in git?

If you made no commits, run git switch main (or the branch you want). If you made commits you want to keep, run git switch -c new-branch-name first, then merge that branch.

How do I recover commits made in detached HEAD?

Run git reflog, find the hash of your last commit, and run git branch rescued <hash>. Unreferenced commits are normally kept for weeks before git deletes them.

Why does checking out a tag give detached HEAD?

A tag is a fixed label on one commit and never moves. Since a new commit can't move the tag, git points HEAD directly at the commit. Use git switch -c branch-name v2.1.0 if you want to make changes starting from a tag.

Published .

Try it

Related guides

Newest guides