Skip to content

Fix: Git Detached HEAD State – How to Reattach and Save Your Work

FixDevs · (Updated: )

Part of:  Docker, DevOps & Infrastructure

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 message

Or 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 clean

If 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> f4e5d6c

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 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 a1b2c3d

This 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.0

Tags 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/main

This 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.

Diagnostic Timeline: What Real Debugging Looks Like

The message “You are in ‘detached HEAD’ state” looks alarming on the first read. It is not an error and Git is not broken. You arrived here on purpose, the message is descriptive, and the only real question is whether you have made commits in this state that need preserving. Here is the order to think through it.

First suspicion: something is broken. Read the message. Git is telling you the current state, not reporting a failure. Run git status — if it says HEAD detached at <hash> and nothing to commit, working tree clean, the repository is healthy. You’re parked on a commit instead of a branch, and you can walk away by running git switch <branch-name> whenever you want. If you came here from git checkout v2.1.0 to read code from a release, switch back to your branch and there is nothing to fix.

Second suspicion: you’ve lost commits you made here. This is the question that actually matters. Check with git log --oneline -5 — the commits at the top are the ones reachable from your current HEAD. If you see commits that aren’t on main (compare with git log --oneline main -5), those are commits you made in detached HEAD and they need a home before you switch away. Save them with git branch <name> HEAD while you’re still parked on them — that creates a branch pointing at the current commit, and now the commits are reachable from a branch reference and won’t be garbage-collected.

Third suspicion: a submodule put you here. If the detachment happened after git submodule update, this is by design. Git checks out the exact submodule commit recorded in the parent repo, which is a hash, not a branch. The check is git rev-parse --show-superproject-working-tree — if it returns a path, you’re inside a submodule. The fix when you want to edit submodule code is git switch main inside the submodule, make your commit, then update the parent’s submodule pointer.

The actual root cause for the panicked case: an interrupted rebase or a stale checkout you forgot about. If you ran git rebase -i two hours ago, hit a conflict, and walked away from the terminal, Git is sitting in detached HEAD waiting for git rebase --continue or git rebase --abort. The signal is git status showing “interactive rebase in progress” or a .git/rebase-merge/ directory. The fix is to finish what you started — never switch branches with a rebase in progress because the partial state stays in .git/ and will trip the next rebase.

The safety net for everything in this category is git reflog. It records every move HEAD has made for the last 30 days (90 in many configs). If you switched away from detached HEAD and Git warned you that you were leaving N commits behind, those commits still exist — git reflog will show them, and git branch recovered <hash> brings them back into the reachable graph. Commits are only truly lost after git gc runs and the reflog entry expires, which doesn’t happen for at least 30 days. Stay calm, run git reflog, recover the commit, attach a branch. Detached HEAD is a feature, not a fault.

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 main

Or using the older checkout syntax:

git checkout main

Replace main with whatever branch you want to return to. You can see all available branches with:

git branch

This 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 --abort

Aborting 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-branch

Or using the older syntax:

git checkout -b my-new-branch

This 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-branch

If 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 -5

You will see output like:

f4e5d6c (HEAD) Add input validation
b7a8c9d Update user model
e1f2a3b Fix authentication bug
a1b2c3d (origin/main, main) Previous commit on main

The 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 main

Step 3: Cherry-pick each commit in order (oldest first):

git cherry-pick e1f2a3b
git cherry-pick b7a8c9d
git cherry-pick f4e5d6c

Or cherry-pick a range:

git cherry-pick e1f2a3b^..f4e5d6c

Each 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 non-fast-forward 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 reflog

The 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 a1b2c3d

The 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 f4e5d6c

Step 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-work

All 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 HEAD

Now 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 main

Fix 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-login

The 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-login

If you need to check out a remote branch with a different local name:

git switch -c my-local-name origin/feature-login

If you encounter permission issues with the remote, the cause is usually a missing or wrong SSH key for the remote host — not a detached HEAD problem. Test the SSH path with ssh -T [email protected] to confirm authentication independently of any branch state.

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 switch instead of git checkout. The switch command was introduced in Git 2.23 specifically to avoid accidental detached HEAD. Running git switch v2.1.0 gives an error instead of silently detaching, forcing you to use git switch -c branch-name v2.1.0 if you want to work from that point.

  • Use git log or git show to 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 HEAD
  • Never check out origin/branch directly. Always use the local branch name without the origin/ prefix. Let Git create the tracking branch for you.

  • After git bisect, always run git 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 --continue after resolving conflicts, or git rebase --abort to 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 status

If 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 --abort

Then 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-reflogs

This 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 main

Make 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 file too large to push for guidance on handling large files in Git.

Worktree confusion makes HEAD look detached when it isn’t

git worktree lets you have multiple working directories pointing at the same repository, and each worktree has its own HEAD. A branch checked out in one worktree cannot be checked out in another — Git refuses with fatal: 'main' is already checked out at .... People sometimes work around this by checking out the commit hash instead, which silently puts the second worktree into detached HEAD. List worktrees with git worktree list and confirm which one owns the branch. Either delete the redundant worktree (git worktree remove <path>) or use a different branch name in the new worktree.

git stash pop after recovery introduces a conflict

After you recover commits with git branch recovered <hash> and merge them in, a git stash pop of work you had set aside earlier can introduce a conflict because the stash was made against a different base. Resolve the conflict in the working tree, run git stash drop if the pop succeeded with conflicts (it leaves the stash in place), and commit the resolution. Check git stash list to confirm nothing is unintentionally left behind.

HEAD looks detached but the prompt is lying

Some shell prompt themes (Oh My Zsh’s git plugin, Starship, Powerlevel10k) display a commit hash when they can’t determine the branch name quickly. If your prompt shows (a1b2c3d) but git status shows On branch main, the prompt is stale. Refresh it (open a new shell, or call the prompt theme’s refresh function). The repository is fine.


Related: Fix: fatal: not a git repository · Fix: git push rejected non-fast-forward · Fix: Merge conflict in file

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles