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 4a2b3c1HEAD detached from v2.1.0When 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> 4a2b3c1Why 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 abc1234puts you at that exact commit, not on a branch. - Checking out a tag. Running
git checkout v1.0.0checks 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/mainchecks out the remote tracking ref directly instead of creating a localmainbranch. (The correct command isgit checkout main, which auto-creates a local branch trackingorigin/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 abc1234means HEAD is still pointing at the commit you originally checked out. You have not made any new commits since detaching.HEAD detached from abc1234means you detached atabc1234but 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-branchOr with the newer switch command:
git switch -c my-new-branchHEAD 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 mainOr:
git switch mainReplace 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 popIf 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-branchThis 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-branchAfter merging, you can delete the temporary branch:
git branch -d temp-branchOption 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 --onelineCopy the hashes you need. Then switch to your target branch and cherry-pick them:
git checkout main
git cherry-pick 4a2b3c1
git cherry-pick 8d3f2a0Each 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 reflogYou 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 c91e4b7The 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 4a2b3c1Step 3: Merge or cherry-pick those commits into your branch:
git checkout main
git merge recovered-workOr 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.0to 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 commitThen 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 resetThis 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-foundThis 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 4a2b3c1d5e6f7890abcdef1234567890abcdef12Inspect each one:
git show 4a2b3c1If it is the commit you want, create a branch from it:
git branch recovered 4a2b3c1Force 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 mainRelated Articles
Fix: CONFLICT (content): Merge conflict in file — fix conflicts and then commit the result
How to fix Git merge conflicts during merge, rebase, cherry-pick, and pull — resolve conflict markers, use merge tools, accept theirs or ours, abort, and prevent future conflicts.
Fix: fatal: not a git repository (or any of the parent directories): .git
How to fix the 'fatal: not a git repository' error in Git by checking your working directory, initializing a repo, recovering a deleted .git folder, and resolving submodule, CI/CD, and IDE path issues.
Fix: git stash pop – CONFLICT, local changes would be overwritten, no stash entries found
How to fix git stash errors: 'CONFLICT' after git stash pop, 'Your local changes to the following files would be overwritten', 'No stash entries found', and 'Could not restore untracked files from stash entry'. Covers stash pop vs apply, conflict resolution, recovering dropped stashes, and stashing untracked files.
Fix: CONFLICT (content): Merge conflict in [file] – Automatic merge failed
How to fix Git merge conflicts: 'CONFLICT (content): Merge conflict in [file]', 'Automatic merge failed; fix conflicts and then commit the result', 'You have unmerged paths', and 'needs merge'. Covers manual resolution, VS Code, --theirs/--ours, merge --abort, mergetool, rebase conflicts, and prevention.