Introduction
You're checking out an old commit to inspect a bug fix from three months ago, and suddenly Git tells you that you're in a "detached HEAD" state. It sounds ominous, like something broke, but in reality, detached HEAD explained: real-world lessons and examples shows us that this is one of Git's most misunderstood features—not a bug, but a tool we can use deliberately. Understanding when and why it happens, and how to recover gracefully, is a skill that separates developers who fight Git from those who work with it.
HEAD points to a commit, not a branch
To understand detached HEAD, we need to first clarify what HEAD actually is. In Git, HEAD is a reference that points to the current commit you're working on. Normally, HEAD points indirectly to a commit by pointing to a branch, which in turn points to a commit. When you're on the main branch, HEAD → main → commit abc123.
A detached HEAD happens when HEAD points directly to a commit, bypassing the branch layer entirely. Now HEAD → commit abc123, with no branch in between. This is perfectly valid—Git doesn't care whether you arrived at a commit via a branch reference or directly—but it's unusual enough that Git warns you about it.
Why does this distinction matter? Because a branch is a moving target. When you make a new commit on main, the main reference advances to that new commit. When you're detached, there's no reference to advance, so new commits you make exist in a limbo state. They're real commits with real hashes, but they're not on any branch, and if you switch away, they become orphaned.
Happens when checking out a tag or commit
The most common scenario: you need to debug a production incident. The team mentions that version 2.5.0 had the issue, and version 2.6.0 fixed it. You check out the tag.
git checkout v2.5.0Git responds:
Note: checking out 'v2.5.0'.
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 branch 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
HEAD is now at 7a2c5e9 Release v2.5.0You're now at the exact commit that was tagged v2.5.0. This is useful for testing, but you're detached. The same thing happens when you check out a specific commit hash:
git checkout 7a2c5e9Tags are immutable pointers to commits, so checking them out will always detach you. Commits are single points in history, so checking them out directly also detaches you. Branches, however, are moving references, so checking out a branch keeps you attached.
In a real scenario, you might be investigating why a feature worked in production three releases ago. You check out the tag, spin up the app, reproduce the behavior, and confirm the bug is still there. You've gained the information you needed without creating any new commits. Then you switch back to develop and move on. Detached HEAD served its purpose.
New commits are not on any branch
Here's where it gets interesting. Suppose you're in that detached HEAD state at v2.5.0, and you spot the bug. You make a fix:
git checkout v2.5.0
# You're detached. Make some changes...
git add .
git commit -m "Fix buffer overflow in auth handler"Git creates the commit successfully. You have a brand-new commit with a hash, say, abc1234. But it's not on main. It's not on develop. It's not on any branch. It's floating in space, reachable only by its hash.
Now imagine you accidentally do this:
git checkout mainYou're back on main, and HEAD now points to the main branch. The commit abc1234 still exists in your repository—it hasn't been deleted—but there's no branch reference pointing to it. If you run git log, you won't see it. If you do git reflog, you might see it temporarily in the reflog, but after Git's garbage collection runs (typically after 30 days of inactivity), the orphaned commit will be pruned.
This is the real danger of detached HEAD: not that it's broken, but that it's easy to accidentally lose work. The fix is simple, though: save your work before switching away.
git switch -c new-branch saves them
The best practice is to convert your detached state into a proper branch the moment you realize you're making real commits. If you've made changes while detached and want to keep them, create a branch right there:
git switch -c bugfix/auth-buffer-overflowThis command does two things: it creates a new branch called bugfix/auth-buffer-overflow pointing to your current commit (abc1234), and it moves HEAD to point to that branch instead of the commit directly. Now you're no longer detached, and your work is safe on a proper branch.
The older syntax also works:
git checkout -b bugfix/auth-buffer-overflowBut git switch -c is the modern, recommended approach. It's clearer in intent: you're switching to a new branch, not checking out a commit.
Let's walk through a realistic workflow. You're debugging an issue in production:
# Step 1: Check out the tag to reproduce the issue
git checkout v2.5.0
# Step 2: Investigate, make a fix
# ... edit files ...
git add .
git commit -m "Reproduce and patch the auth bug"
# Step 3: Realize this is important work
git status
# On branch HEAD detached at 7a2c5e9
# Step 4: Save your work to a branch
git switch -c bugfix/v2.5-auth-issue
# Step 5: You're now on a branch. Push it.
git push origin bugfix/v2.5-auth-issue
The commit is now safe. It's on a branch, it's pushed to the remote, and the team can review it.
Common mistakes
Forgetting you're detached and switching branches: You make commits while detached, feel confident about your changes, then git checkout main to prepare for a push. Those commits are now orphaned. Always check git status before switching. If you see "HEAD detached," run git switch -c before moving on.
Assuming detached HEAD broke something: It didn't. Detached HEAD is a state, not a corruption. Your repository is fine. Your commits are real. You just need to attach them to a branch if you want to keep them.
Making experimental changes without creating a temporary branch: If you're testing a hypothesis on an old commit, it's fine to stay detached as long as you don't commit. If you do decide to commit, immediately create a branch. Don't assume "I'll remember to branch later"—do it now.
Not using git reflog when panic sets in: If you do accidentally lose a detached commit, git reflog will often show it. Reflog keeps a history of where HEAD has been, so you can recover the commit hash and create a branch from it, even if the commit is no longer reachable via any branch.
Key takeaways
- HEAD is a reference that usually points to a branch, which points to a commit. When HEAD points directly to a commit, you're detached.
- Detached HEAD happens when you check out a tag or a specific commit hash, not when you check out a branch.
- Commits made while detached are real and safe in the repository, but they're not on any branch and can be lost if you switch away without saving them.
- Use
git switch -c new-branchto instantly convert a detached state into a proper branch and protect your work. - Always run
git statusbefore switching branches. If you see "HEAD detached," decide whether to commit your changes and save them to a branch, or discard them. - Detached HEAD is a feature, not a bug. Many workflows deliberately use it for testing, tagging, or bisecting. Only treat it as a problem if you've made commits you want to keep.






Comments
Loading comments…