Gitastic
Path › Part 4: Undo & rescue › Lesson 13 of 16
13

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

Get lost, get found

Press Play or use → to step through. Watch the graph as each command runs.

2f5672f Add menu2f5672fAdd menue375f09 Add pricese375f09Add prices5649ea0 Add desserts5649ea0Add dessertsHEAD = where you are. It points at the current branch.HEAD →Branch "main" — a movable pointer (current branch: moves when you commit)main
terminal · simulated, no real repository is touched
Read this demo as text
  1. $ git checkout HEAD~2

    We check out an old commit directly. The HEAD label leaves main and sits on the commit by itself: detached HEAD.

  2. $ 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.

  3. $ 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.

  4. $ git reflog

    The flight recorder: every HEAD move, newest first. HEAD@{1} is our "Try vegan menu" commit.

  5. $ git switch -c vegan HEAD@{1}

    We create a branch at that reflog entry. The commit is saved, with a real name now.

  6. $ git switch main

    Now the second scare: back on main…

  7. $ git reset --hard HEAD~2

    …we reset two commits too far. "Add prices" and "Add desserts" disappear from main and grey out.

  8. $ git reflog

    The reflog still has them: HEAD@{1} is where main was right before the reset.

  9. $ 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.

  1. Stop. Do not keep running commands in a panic.
  2. Run git reflog and find the line from just before things went wrong.
  3. Either move your branch back: git reset --hard HEAD@{n}…
  4. …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 branch
git reflogList every place HEAD has been
git reset --hard HEAD@{n}Jump the branch back to a reflog entry

3 Check your understanding

Question 1

Look at the graph. What state is this repository in?

2f5672f Add menu2f5672fAdd menue375f09 Add pricese375f09Add pricesHEAD points straight at a commit (no branch). New commits here are easy to lose!HEAD (detached)Branch "main" — a movable pointermain
Question 2

You made two commits in detached HEAD and want to keep them. What do you run?

Question 3

After git reset --hard HEAD~3 you realise you needed those commits. What is the most direct fix?

Question 4

Which of these can the reflog NOT recover?

4 Practice for real

Your mission

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.

2f5672f Add menu click to insert the hash into the terminal2f5672fAdd menue375f09 Add prices (unreachable: no branch points here any more — only the reflog remembers it) click to insert the hash into the terminale375f09Add prices5649ea0 Add desserts (unreachable: no branch points here any more — only the reflog remembers it) click to insert the hash into the terminal5649ea0Add desserts74330ac Add drinks click to insert the hash into the terminal74330acAdd drinksHEAD = where you are. It points at the current branch.HEAD →Branch "main" — a movable pointer (current branch: moves when you commit)main
terminal · simulated, no real repository is touched
Type commands below. `help` lists everything. Tab completes, ↑ recalls. Click a commit to paste its hash.
~/project (main) $