Detached HEAD & the reflog safety net
Commits are very hard to truly lose, and here is why.
1 Learn the idea
Two scary moments: git says "You are in 'detached HEAD' state", or you run git reset --hard and your commits seem to vanish. Both are much less dangerous than they look.
Detached HEAD
Normally HEAD points to a branch, and the branch points to a commit. When you check out a commit directly (git checkout a1b2c3d, or git switch --detach), HEAD points straight at the commit with no branch in between. You can look around and even commit, but no branch label follows along. If you switch away, those new commits have no name. They are not deleted, only harder to find.
2 Watch it happen
Press Play or use → to step through. Watch the graph as each command runs.
Read this demo as text
$ git checkout HEAD~2
We check out an old commit directly. The HEAD label leaves
mainand sits on the commit by itself: detached HEAD.$ echo "Tofu soup" > vegan.md $ git add vegan.md $ git commit -m "Try vegan menu"
Committing in detached HEAD works. Only HEAD moves with the new commit, and no branch follows it.
$ git switch main
We switch back to main. The experiment commit greys out: nothing points at it any more. It still exists, but it is hard to find.
$ git reflog
The flight recorder: every HEAD move, newest first.
HEAD@{1}is our "Try vegan menu" commit.$ git switch -c vegan HEAD@{1}We create a branch at that reflog entry. The commit is saved, with a real name now.
$ git switch main
Now the second scare: back on main…
$ git reset --hard HEAD~2
…we reset two commits too far. "Add prices" and "Add desserts" disappear from main and grey out.
$ git reflog
The reflog still has them:
HEAD@{1}is where main was right before the reset.$ git reset --hard HEAD@{1}We reset back to it and main is whole again. The same trick undoes a bad rebase, amend or merge.
- Stop. Do not keep running commands in a panic.
- Run
git reflogand find the line from just before things went wrong. - Either move your branch back:
git reset --hard HEAD@{n}… - …or rescue it on the side without touching anything:
git branch rescue <hash>.
git switch --detach <commit>Look at an old commit (detached HEAD)git switch -c <name>Turn where you are into a branchgit reflogList every place HEAD has beengit reset --hard HEAD@{n}Jump the branch back to a reflog entry3 Check your understanding
Look at the graph. What state is this repository in?
You made two commits in detached HEAD and want to keep them. What do you run?
After git reset --hard HEAD~3 you realise you needed those commits. What is the most direct fix?
Which of these can the reflog NOT recover?
4 Practice for real
Undo the disaster
Someone ran git reset --hard HEAD~2 on main, then committed "Add drinks" on top. Get "Add prices" and "Add desserts" back into main without losing "Add drinks". End on main with a clean tree.