Git Detached HEAD — What It Is and How to Fix It
Git dropped you into "detached HEAD" and the commits you just made seem to have vanished. Here's what happened and how to get your work back.
Key takeaways
- Git dropped you into "detached HEAD" and the commits you just made seem to have vanished.
- Here's what happened and how to get your work back.
On this page
Git Detached HEAD — What It Is and How to Fix It#
I still remember the first time this bit me. I'd checked out an old commit to confirm a bug existed before a certain release, fixed it right there because I was already looking at the code, committed, and pushed nothing because I got pulled into a meeting. Came back an hour later, ran git switch main, and my two commits were gone. Not on any branch. Not in the log. Gone.
They weren't actually gone, but I didn't know that yet. Here's what was going on.
What HEAD normally points at#
HEAD is Git's pointer for "where you are right now." In normal life it points at a branch, like main, and the branch points at a commit. When you make a new commit, the branch moves forward and drags HEAD along with it. That indirection is the whole trick: your branch name follows your work automatically.
Detached HEAD is when that middle step disappears. HEAD points straight at a commit instead of at a branch. You're standing on a specific snapshot with no branch label attached to your position.
You land here a few ways:
git checkout <sha>orgit switch --detach <sha>— jumping to a specific commitgit checkout v1.4.0— checking out a tag (tags aren't branches)git bisect— the whole mechanism walks you across commits detached- Submodules — they're pinned to an exact commit, so a fresh submodule checkout is detached by design
When it happens, Git tells you plainly:
Note: switching to 'a1b2c3d'.
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.
That text is worth reading once, slowly. It's not an error. It's Git warning you about the tradeoff you just accepted.
Why it's a warning, not a failure#
Nothing is broken in detached HEAD. You can read files, run the build, check out a suspicious old commit and reproduce a bug. All of that is fine, and half the time it's exactly why you went there.
The catch is committing. If you make commits in detached HEAD, they exist, but no branch points at them. The only thing pointing at your new work is HEAD itself. The moment you switch to a branch, HEAD moves, and those commits have nothing holding them in place. Git's garbage collection eventually sweeps up unreferenced commits, so "eventually" they really do disappear.
That's the trap I fell into. My two commits were real, they just had no name. Switching branches let go of the only handle I had on them.
Fix 1: you made no commits, just get back#
If you only looked around and didn't commit anything, there's nothing to save. Return to your branch:
git switch main
Or the older spelling, still fine:
git checkout main
Done. No drama. This is the common case and it's why the warning exists but rarely causes real pain.
Fix 2: you made commits and want to keep them#
This is the case that matters. You're in detached HEAD, you committed real work, and you want it to survive. Do NOT switch branches yet. First, give your work a name:
git switch -c fix/old-release-bug
That creates a new branch right where you're standing, and every commit you made in detached state is now on it, safe. HEAD is reattached to a real branch. From here you push, open a PR, merge, whatever you normally do.
The opinionated version of this: create the branch before you commit, not after. The instant you decide you're going to write code in a detached checkout, run git switch -c something first. It costs you nothing, and it turns the whole "lost commits" problem into a non-event. I've never once regretted making a throwaway branch. I've regretted the other choice plenty.
Fix 3: you already switched away and lost the commits#
This is where people panic, and it's the most recoverable situation of all. Your commits aren't in any branch's history, but Git wrote down every place HEAD has ever been. That log is the reflog.
git reflog
You'll get something like:
a1b2c3d HEAD@{0}: checkout: moving from a1b2c3d to main
9f8e7d6 HEAD@{1}: commit: fix null check in parser
3c2b1a0 HEAD@{2}: commit: reproduce the crash
a1b2c3d HEAD@{3}: checkout: moving from main to a1b2c3d
There they are. 9f8e7d6 is the tip of the work I thought I'd lost. Grab it with a branch:
git branch recovered 9f8e7d6
Now switch to it, confirm the log looks right, and carry on. The reflog keeps entries for 90 days by default, so unless you waited a season or ran an aggressive git gc, your commits are sitting there waiting.
When detached HEAD is the right tool#
None of this means detached HEAD is a mistake to avoid. It's genuinely useful. Inspecting an old state to answer "did this bug exist at the v2.0 tag" is cleaner detached than creating a branch you'll throw away. git bisect depends on it. And CI systems check out a specific commit SHA on purpose — a build should be reproducible against an exact snapshot, not against whatever main happens to be right now. If you see detached HEAD in a CI log, that's correct behavior, not a bug in your pipeline.
The rule is simple. Detached HEAD for looking: perfect. Detached HEAD for committing: only after you've made a branch to catch the work.
The call we'd make#
Treat the warning as a checklist, not noise. If you're only inspecting, ignore it and git switch back when you're done. If there's any chance you'll commit, run git switch -c name the second you land, before you touch a file. And if you're reading this because your commits already vanished, breathe, run git reflog, and branch off the SHA — the work is almost certainly still there. For the wider set of these, our Git troubleshooting guide collects the ones that catch people most.
Get the DevOps Troubleshooting Cheat Sheet
Subscribe and get our free one-page reference for the errors that eat an afternoon — CrashLoopBackOff, OOMKilled, Terraform state locks, and more — plus new guides as we publish them.
Detecting and Rotating Leaked Cloud Credentials
Static keys leak. The question isn't if but how fast you notice and how clean your response runbook is when the pager goes off.
Jenkins Pipeline Best Practices in 2026: Builds You Can Trust
A production-focused Jenkins guide: declarative pipelines, shared libraries, ephemeral agents on Kubernetes, scoped credentials, parallel stages, input approvals, post-block rollback and notifications, and Configuration as Code — with copy-paste examples.
More from DevOps
Explore more articles in this category
Best Kubernetes IDE and GUI Tools in 2026
kubectl is fine until you're juggling five namespaces across three clusters. These are the tools that make that manageable, compared.
Chef vs Puppet vs Ansible: Configuration Management in 2026
One is agentless and Python-based, the other two run a persistent agent and a domain-specific language. The architecture difference matters more than the syntax.
PagerDuty vs Opsgenie: Choosing an Incident Alerting Tool
Both page the right person at 3am and both integrate with everything. The real differences show up in pricing structure, workflow depth, and who already owns the ecosystem around you.
You might have missed
Evergreen posts worth revisiting.