Getting Out of Git Detached HEAD — Causes and Recovering Commits

5 min read

You check out a commit hash to look at an old version of the code, and a long, unfamiliar warning appears.

The detached HEAD warning
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.

The sheer length of the warning makes it look like a serious accident, so let’s settle the conclusion first. Detached HEAD is not a malfunction — it is simply the state where HEAD points directly at a commit instead of a branch. The state itself breaks nothing. But if you make commits in this state and walk away without doing anything, you can lose them, so the structure and the exits are worth knowing.

What it means for HEAD to be detached #

Normally HEAD points not at a commit but at a branch. When you commit on main, the main pointer advances to the new commit, and HEAD follows main along automatically.

But when you check out a specific commit hash or a tag directly, rather than a branch, HEAD ends up pointing straight at that commit without a branch in between. It has come off the branch — hence detached, a detached HEAD.

Normal state vs detached state
[normal — attached]
HEAD ──▶ main ──▶ C3

[detached]
HEAD ──────────▶ C1        (no branch in between)

There are roughly three paths into the detached state.

  • Checking out an old commit or a tag directlygit checkout 1a2b3c4, git checkout v2.1.0, or explicitly git switch --detach 1a2b3c4
  • While bisect is running — the binary search checks out one middle commit after another, so you stay detached for the whole hunt. Ending it with git bisect reset puts you back.
  • Inside a submodule — a submodule references a repository pinned to a specific commit by design, so inside that directory you are detached by default.

What the actual risk is — commits that belong to no branch #

If you only read code in the detached state, there is no danger at all. The problem begins when you make commits.

A commit made on a branch stays referenced by the branch pointer. A commit made in the detached state, however, is pointed at by no branch. The moment you leave with git switch main, those fresh commits become unreachable, and in time they become targets for garbage collection. Git knows this, which is why it prints one last warning as you leave.

The warning when leaving after committing in detached state
Warning: you are leaving 2 commits behind, not connected to
any of your branches:

  8f3c2d1 experiment: tune cache size
  5e9a7b4 experiment: print cache stats

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> 8f3c2d1

The warning even spells out the fix. Put a branch on the commits.

Escape routes by situation #

How you get out of detached HEAD splits three ways, depending on what you did while you were there.

If you only looked around — just go back.

Returning to the previous branch
git switch -

- means the branch you were on right before. If you made no commits, this one line ends the situation.

If you made commits and want to keep them — put a branch on them before leaving.

Creating a new branch on the current commit
git switch -c experiment-cache

A new branch is created on the commit HEAD is pointing at, and HEAD reattaches to that branch. The commits are now referenced by a branch, so there is nothing left to lose.

If you already left and lost the commits — find the hash and put a branch on it.

The warning printed as you left has the commit hash in it, so create a branch from that hash.

Recovering with the hash from the warning
git branch experiment-cache 8f3c2d1

If you closed the terminal and lost the warning, search the reflog. Commits made in the detached state are all recorded there too. The procedure for tracking down the hash is covered in Recovering Deleted Git Commits and Branches with reflog.

Note
Detached HEAD inside a submodule is the normal state, not something to escape from. The outer repository references the submodule pinned to a specific commit, so to work inside the submodule you first attach to a branch with git switch <branch> and then commit.

The habit of looking around safely in the first place #

If you have a reason to inspect the code at some point in the past, it is cleaner to create a branch before going in.

Viewing an old point with a branch attached
git switch -c temp-look 1a2b3c4
# when you are done
git switch main
git branch -d temp-look

Since the detached state never comes into being, there is no warning and no chance of losing commits. If you only looked and never committed, deleting the branch cleans everything up without a trace.

Wrap-up #

The key points of this post are three.

  • Detached HEAD is the state where HEAD points directly at a commit instead of a branch, and by itself it breaks nothing.
  • The risk lies only in commits made in this state. Putting a branch on them with git switch -c <branch> before leaving keeps them safe, and if you already left, recover with the hash from the warning or from the reflog.
  • If you create a temporary branch from the start when inspecting old code, you never meet this state at all.

The warning reads as threatening because it is long, but its content is closer to guidance. Once you understand the structure, detached HEAD is not an accident but a free exploration mode that Git provides.

X