Fix: Git Detached HEAD State – How to Reattach and Save Your Work
Quick Answer
How to fix Git's detached HEAD state, reattach to a branch, and recover commits made while in detached HEAD.
The Error
You run a Git command or check git status 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.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
git switch -c <new-branch-name>
Or undo this operation with:
git switch -
HEAD is now at a1b2c3d Some commit messageOr you notice your shell prompt shows a commit hash instead of a branch name:
((a1b2c3d...)) $Running git status confirms the problem:
HEAD detached at a1b2c3d
nothing to commit, working tree cleanIf you already made commits in detached HEAD and then switched away, you may see this warning:
Warning: you are leaving 3 commits behind, not connected to
any of your branches:
f4e5d6c Third commit
b7a8c9d Second commit
e1f2a3b First commit
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> f4e5d6cWhy 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 or feature-login), and the branch name points to the latest commit on that branch. This is called an “attached” HEAD. When you make a new commit, the branch moves forward to include it, and HEAD follows along because it is attached to that branch.
A detached HEAD means HEAD is pointing directly at a specific commit instead of pointing at a branch. Git is fully functional in this state — you can look at files, run tests, and even make commits. But those commits are not on any branch. If you switch to a different branch without saving your work, those commits become unreachable and Git will eventually garbage-collect them.
Here are the most common ways you end up in detached HEAD:
Checking out a specific commit by hash:
git checkout a1b2c3dThis is the most common cause. You wanted to inspect an older commit, and Git moved HEAD directly to that commit instead of a branch.
Checking out a tag:
git checkout v2.1.0Tags are fixed references to specific commits. When you check out a tag, Git detaches HEAD because tags are not branches and do not move forward when you make new commits.
Checking out a remote branch directly:
git checkout origin/mainThis checks out the remote tracking reference directly instead of creating a local branch that tracks it. Since origin/main is not a local branch, HEAD detaches.
Interactive rebase interruption:
During a git rebase -i, Git internally detaches HEAD to replay commits. If the rebase is interrupted by a conflict or if you forget to run git rebase --continue, you may be left in a detached state.
Checking out a commit during bisect:
Running git bisect moves HEAD to various commits to help you find a bug. This is intentional detachment and resolves when you run git bisect reset.
Fix 1: Reattach HEAD by Switching to a Branch
If you have not made any commits while in detached HEAD and simply want to go back to where you were, switch to your branch:
git switch mainOr using the older checkout syntax:
git checkout mainReplace main with whatever branch you want to return to. You can see all available branches with:
git branchThis is the simplest fix. HEAD reattaches to the branch, and you are back to normal. Any uncommitted changes in your working directory will come along with you (or Git will warn you if there are conflicts).
If you ended up in detached HEAD because of an interrupted rebase, do not just switch branches. Instead, complete or abort the rebase:
# Continue the rebase after resolving conflicts
git rebase --continue
# Or abort the rebase entirely
git rebase --abortAborting the rebase returns you to the branch you were on before the rebase started, with HEAD properly attached.
Fix 2: Save Commits by Creating a New Branch
If you made commits while in detached HEAD, switching to an existing branch will abandon those commits. Instead, create a new branch right where you are to preserve them:
git switch -c my-new-branchOr using the older syntax:
git checkout -b my-new-branchThis creates a new branch pointing at your current commit (including any commits you made while detached) and attaches HEAD to it. All your work is safe.
You can then merge this branch into your main branch whenever you are ready:
git switch main
git merge my-new-branchIf the merge produces conflicts, see Fix: Merge conflict in file for resolution steps.
Fix 3: Move Your Commits to an Existing Branch
If you made commits in detached HEAD and want to add them to an existing branch rather than creating a new one, you can cherry-pick them.
Step 1: While still in detached HEAD, note the commit hashes you want to keep:
git log --oneline -5You will see output like:
f4e5d6c (HEAD) Add input validation
b7a8c9d Update user model
e1f2a3b Fix authentication bug
a1b2c3d (origin/main, main) Previous commit on mainThe commits above a1b2c3d are the ones you made while detached. Write down their hashes.
Step 2: Switch to the branch you want to apply them to:
git switch mainStep 3: Cherry-pick each commit in order (oldest first):
git cherry-pick e1f2a3b
git cherry-pick b7a8c9d
git cherry-pick f4e5d6cOr cherry-pick a range:
git cherry-pick e1f2a3b^..f4e5d6cEach cherry-pick applies the changes from that commit onto your current branch as a new commit. If a cherry-pick causes a conflict, Git will pause and ask you to resolve it. After resolving, run git cherry-pick --continue.
If you encounter issues pushing the branch after cherry-picking, see Fix: git push rejected for solutions.
Fix 4: Recover Lost Commits with git reflog
If you already switched away from detached HEAD without saving your commits, Git printed a warning with the commit hashes. But if you missed that warning or cleared your terminal, the commits still exist in Git’s reflog for at least 30 days.
Step 1: Open the reflog:
git reflogThe reflog records every time HEAD changed position. You will see entries like:
a1b2c3d (HEAD -> main) HEAD@{0}: checkout: moving from f4e5d6c to main
f4e5d6c HEAD@{1}: commit: Add input validation
b7a8c9d HEAD@{2}: commit: Update user model
e1f2a3b HEAD@{3}: commit: Fix authentication bug
a1b2c3d (HEAD -> main) HEAD@{4}: checkout: moving from main to a1b2c3dThe entries with commit: messages are your detached HEAD commits. The most recent one (f4e5d6c in this example) is the tip of your lost work.
Step 2: Create a branch at the lost commit:
git branch recovered-work f4e5d6cStep 3: Switch to it or merge it:
# Option A: Switch to the recovered branch
git switch recovered-work
# Option B: Merge it into your current branch
git merge recovered-workAll your commits are back. The reflog is your safety net — as long as a commit was made, Git remembers it for at least 30 days regardless of whether it belongs to a branch.
Step 4: If the reflog output is long and hard to read, filter it to show only commit actions:
git reflog --grep-reflog="commit:"Or search for a keyword from your commit messages:
git reflog --grep-reflog="validation"Fix 5: Reattach HEAD After Checking Out a Tag
If you checked out a tag and want to work from that point, create a branch at the tag:
git checkout v2.1.0 # Detaches HEAD at the tag
git switch -c hotfix/v2.1.1 # Creates a branch and reattaches HEADNow you can make commits normally. The branch starts at the same commit the tag points to, but unlike the tag, the branch will move forward as you commit.
If you just wanted to look at the tagged code without making changes, switch back to your branch when you are done:
git switch mainFix 6: Properly Check Out a Remote Branch
If you accidentally detached HEAD by checking out a remote branch directly, the fix is to create a local tracking branch:
# This causes detached HEAD:
git checkout origin/feature-login
# This is what you should do instead:
git switch feature-loginThe git switch command (and git checkout without the origin/ prefix) automatically creates a local branch that tracks the remote branch, as long as the branch name matches exactly one remote branch.
If the local branch already exists and you want to reset it to match the remote:
git switch feature-login
git reset --hard origin/feature-loginIf you need to check out a remote branch with a different local name:
git switch -c my-local-name origin/feature-loginIf you encounter permission issues with the remote, see Fix: Permission denied (publickey) for SSH troubleshooting.
Common Mistake: After cherry-picking commits from detached HEAD, developers often forget to verify the order. Cherry-picks must be applied oldest-first, or you risk introducing conflicts that wouldn’t otherwise exist.
Preventing Detached HEAD
Detached HEAD is not dangerous — it is a normal Git state. But it catches people off guard, and commits made in detached HEAD are easy to lose. Here are habits that prevent accidental detachment:
Use
git switchinstead ofgit checkout. Theswitchcommand was introduced in Git 2.23 specifically to avoid accidental detached HEAD. Runninggit switch v2.1.0gives an error instead of silently detaching, forcing you to usegit switch -c branch-name v2.1.0if you want to work from that point.Use
git logorgit showto inspect old commits instead of checking them out. If you just want to see what a commit changed, you do not need to check it out:
# View a commit's changes without checking it out
git show a1b2c3d
# View the full file at that commit without checking it out
git show a1b2c3d:src/app.js
# Compare a commit with current HEAD
git diff a1b2c3d HEADNever check out
origin/branchdirectly. Always use the local branch name without theorigin/prefix. Let Git create the tracking branch for you.After
git bisect, always rungit bisect reset. This reattaches HEAD to the branch you were on before the bisect.After a rebase conflict, always finish the rebase. Run
git rebase --continueafter resolving conflicts, orgit rebase --abortto cancel. Do not leave a rebase half-finished.Pay attention to Git’s warnings. Git tells you when you enter detached HEAD and tells you when you are leaving commits behind. Read the messages in your terminal — they contain the exact commands you need to save your work.
Why this matters: Commits made in detached HEAD are not protected by any branch reference. Git’s garbage collector will permanently delete them after 30 days if they remain unreachable. Unlike branch commits, there is no remote backup unless you explicitly push them somewhere.
Still Not Working?
HEAD detached after a failed merge or pull
If a merge or pull operation left you in detached HEAD, the operation may have been interrupted. Check the state:
git statusIf you see “rebase in progress” or “merge in progress,” complete or abort the operation:
# For an in-progress merge
git merge --abort
# For an in-progress rebase
git rebase --abortThen switch back to your branch.
Commits are gone and not in reflog
If more than 90 days have passed since the detached commits were created, Git may have garbage-collected them. You can try to find unreachable commits with:
git fsck --unreachable --no-reflogsThis searches Git’s object database for commits that no branch or tag points to. If your commits appear in the output, create a branch at them:
git branch recovered <commit-hash>If git fsck does not find them, the commits have been permanently removed by garbage collection.
Detached HEAD inside a submodule
Submodules are frequently in detached HEAD by design. When you run git submodule update, Git checks out the specific commit recorded in the parent repository, which detaches HEAD inside the submodule.
If you need to make changes inside a submodule, switch to a branch first:
cd path/to/submodule
git switch mainMake your changes and commit. Then go back to the parent repository and update the submodule reference:
cd ..
git add path/to/submodule
git commit -m "Update submodule to latest"Your project is not a Git repository
If git status shows errors beyond the detached HEAD message, you may not be inside a Git repository at all. See Fix: fatal: not a git repository for troubleshooting that problem.
Detached HEAD after checking out a file path
Running git checkout -- file.txt does not detach HEAD. It discards changes to that file. But running git checkout <hash> -- file.txt also does not detach HEAD — it just restores that file from the specified commit. Detached HEAD only happens when you check out a commit, tag, or remote reference without a file path. If you are seeing detached HEAD, you likely ran git checkout <hash> without specifying a file, which checks out the entire commit.
Large files causing issues during recovery
If your detached HEAD commits included large files that are causing problems during cherry-pick or merge, see Fix: Git large file error for guidance on handling large files in Git.
Related: Fix: fatal: not a git repository · Fix: git push rejected · Fix: Merge conflict in file
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Git submodule update failed / fatal: not a git repository
Resolve Git submodule update and init failures including 'fatal: not a git repository', path conflicts, URL mismatches, shallow clone issues, and CI/CD checkout problems.
Fix: Git "cannot lock ref" – Unable to Create Lock File
How to fix the Git error 'cannot lock ref: Unable to create .git/refs/heads/branch-name.lock' caused by stale lock files, case conflicts, packed-refs corruption, and concurrent operations.
Fix: git cherry-pick error: could not apply commit (conflict)
How to fix git cherry-pick conflict errors caused by diverged branches, overlapping changes, missing context, renamed files, and merge commits.
Fix: error: failed to push some refs to remote
How to fix Git error 'failed to push some refs' caused by diverged branches, remote changes, protected branches, authentication failures, and pre-push hooks.