Skip to content

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

FixDevs ·

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.

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

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