Fix: You are in 'detached HEAD' state

The Error

You run git status or git checkout and see:

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.

Or you see one of these in your shell prompt or git status output:

HEAD detached at 4a2b3c1
HEAD detached from v2.1.0

When you switch away from the detached HEAD, Git may warn you:

Warning: you are leaving 3 commits behind, not connected to
any of your branches:

  4a2b3c1 Add feature X
  8d3f2a0 Fix bug in parser
  c91e4b7 Update config

If you want to keep them by creating a new branch, this may be a good time
to do so with:

 git branch <new-branch-name> 4a2b3c1

Why This Happens

In Git, HEAD is a pointer that tells Git which commit you are currently working on. Normally, HEAD points to a branch name (like main), and that branch in turn points to a commit. When you make a new commit, the branch moves forward to the new commit, and HEAD follows along because it is attached to the branch.

In a detached HEAD state, HEAD points directly to a commit instead of a branch. You can still look at files, make changes, and even create commits. But those commits are not on any branch. If you switch to a different branch without saving your work, those commits become orphaned and will eventually be garbage-collected by Git.

Here is what causes it:

  • Checking out a specific commit hash. Running git checkout abc1234 puts you at that exact commit, not on a branch.
  • Checking out a tag. Running git checkout v1.0.0 checks out the tagged commit directly. Tags are not branches, so HEAD detaches.
  • Checking out a remote branch without creating a local branch. Running git checkout origin/main checks out the remote tracking ref directly instead of creating a local main branch. (The correct command is git checkout main, which auto-creates a local branch tracking origin/main.)
  • Submodule checkouts. Git checks out submodules at a specific commit by design. Inside a submodule, detached HEAD is the default state.
  • Interactive rebase or bisect. Git temporarily detaches HEAD while it replays commits or walks through history.

”HEAD detached at” vs “HEAD detached from”

There is a subtle difference between these two messages:

  • HEAD detached at abc1234 means HEAD is still pointing at the commit you originally checked out. You have not made any new commits since detaching.
  • HEAD detached from abc1234 means you detached at abc1234 but then made new commits. HEAD has moved forward from the original detach point. Those new commits are not on any branch.

The “detached from” message is the more urgent one. It means you have work that exists only in the detached state.

Fix 1: Create a New Branch from Detached HEAD

If you are in a detached HEAD state and want to keep working from this point, create a branch right where you are:

git checkout -b my-new-branch

Or with the newer switch command:

git switch -c my-new-branch

HEAD is now attached to my-new-branch. Any commits you already made while detached are now part of this branch. Any new commits will be added to this branch as normal.

This is the simplest fix and works whether or not you have made commits in the detached state.

Fix 2: Go Back to an Existing Branch

If you ended up in detached HEAD by accident and have not made any changes you want to keep, switch back to your branch:

git checkout main

Or:

git switch main

Replace main with whatever branch you want to return to. HEAD reattaches to that branch and you are back to normal.

If you have uncommitted changes in the working directory, Git may refuse to switch branches. Either commit them first, stash them, or discard them:

# Stash changes, switch, then optionally apply them
git stash
git checkout main
git stash pop

If you run into issues when popping the stash, see Fix: git stash pop conflicts.

Fix 3: Save Commits Made in Detached HEAD Before Switching

If you made commits while in detached HEAD and want to preserve them, you have two options.

Option A: Create a branch, then merge

First, save the detached commits to a new branch:

git branch temp-branch

This creates temp-branch pointing at your current commit (including all commits you made while detached) without switching to it. Now switch to your target branch and merge:

git checkout main
git merge temp-branch

After merging, you can delete the temporary branch:

git branch -d temp-branch

Option B: Cherry-pick specific commits

If you only want some of the commits you made while detached, note their hashes before switching branches:

git log --oneline

Copy the hashes you need. Then switch to your target branch and cherry-pick them:

git checkout main
git cherry-pick 4a2b3c1
git cherry-pick 8d3f2a0

Each cherry-pick applies a single commit to your current branch. If the cherry-pick or merge produces conflicts, see Fix: merge conflict for resolution steps.

Fix 4: Recover Lost Commits After Leaving Detached HEAD

If you already switched branches and got the “you are leaving X commits behind” warning (or you switched without noticing), those commits are not gone yet. Git keeps a record of every place HEAD has pointed to in the reflog.

Step 1: Find the lost commits:

git reflog

You will see output like:

a1b2c3d HEAD@{0}: checkout: moving from 4a2b3c1 to main
4a2b3c1 HEAD@{1}: commit: Add feature X
8d3f2a0 HEAD@{2}: commit: Fix bug in parser
c91e4b7 HEAD@{3}: checkout: moving from main to c91e4b7

The commit hashes on the left are your lost commits. HEAD@{1} is the most recent one.

Step 2: Create a branch from the lost commit:

git branch recovered-work 4a2b3c1

Step 3: Merge or cherry-pick those commits into your branch:

git checkout main
git merge recovered-work

Or cherry-pick individual commits if you prefer.

Important: Reflog entries expire after 90 days by default (30 days for unreachable commits). Recover your work sooner rather than later.

When Detached HEAD Is Intentional

Not every detached HEAD needs fixing. These scenarios are normal:

  • Inspecting old code. You want to see what the code looked like at a specific commit or tag. Check it out, look around, then switch back to your branch. No fix needed.
  • CI/CD pipelines. Most CI systems check out a specific commit hash, not a branch. Detached HEAD is expected. Build scripts should not need to be on a branch.
  • Checking out a release tag. Running git checkout v2.0.0 to inspect a release is fine. You are reading, not writing.
  • Read-only exploration. If you are not making commits, detached HEAD is harmless. Switch back to a branch when you are done.

The rule is simple: if you are going to make commits, attach HEAD to a branch first. If you are just looking, detached HEAD is fine.

Still Not Working?

Submodule is always in detached HEAD

This is normal. Git submodules check out a specific commit recorded by the parent repository, not a branch. When you cd into a submodule, git status will always show detached HEAD.

If you need to make changes inside a submodule, check out a branch first:

cd my-submodule
git checkout main
# make your changes and commit

Then go back to the parent repo and commit the updated submodule reference:

cd ..
git add my-submodule
git commit -m "Update submodule to latest"

Be aware that running git submodule update from the parent will put the submodule back into detached HEAD at the recorded commit. This is by design.

Git bisect leaves you in detached HEAD

When you run git bisect, Git checks out commits in a binary search pattern to find a bug. Each step puts you in detached HEAD. This is expected.

When you are done bisecting:

git bisect reset

This returns you to the branch you were on before you started bisecting. Do not try to “fix” detached HEAD during a bisect — it is part of the process.

Recovering commits when reflog is empty

If the reflog does not show your lost commits (e.g., they expired, or you are on a different machine), you can try:

git fsck --lost-found

This searches the Git object database for dangling commits — commits that are not reachable from any branch or tag. The output will look like:

dangling commit 4a2b3c1d5e6f7890abcdef1234567890abcdef12

Inspect each one:

git show 4a2b3c1

If it is the commit you want, create a branch from it:

git branch recovered 4a2b3c1

Force checkout lost uncommitted changes

If you switched branches with git checkout -f or git checkout --force and lost uncommitted changes (not committed, just edited files), those changes are gone. Git did not track them, and there is nothing to recover.

This is different from losing commits made in detached HEAD (which are recoverable via reflog). Uncommitted changes that were forcefully discarded cannot be retrieved through Git.

To avoid this in the future, always stash or commit your work before switching branches:

git stash
git checkout main

Related: Fix: git push rejected – non-fast-forward error

Related Articles