Master

Undoing anything, eventually

The reflog is git's black box from a crashed plane. Once I lost a branch by resetting the wrong commit, it was the only thing that brought it back.

What you will see

main recovered

About 2 min of reading

Quick check

Before this new lesson, one small question about the lesson you just finished. Recall it, do not look it up.

Try It

Use the reflog to find and restore anything git has lost. After a destructive reset I used the reflog to track down the commit it buried and bring it back with a branch.

1

Build a small history, then destroy the last commit with a hard reset. The working folder and branch move back, but the lost commit still exists in git's ledger.

printf 'v1\n' > app.py git add app.py git commit -m initial printf 'v2\n' > app.py git add app.py git commit -m second git reset --hard HEAD~1

Before you run it, say out loud what it will print. Then open the answer.

What it prints
HEAD is now at abc4309 initial
The `second` commit is gone from the branch, but reflog remembers every HEAD movement, including this reset, so the lost commit is not truly gone yet.
2

Show the reflog. Every change to HEAD is listed with an index number, oldest at the bottom. The lost commit appears right after the reset that buried it.

git reflog

Before you run it, say out loud what it will print. Then open the answer.

What it prints
abc4309 HEAD@{0}: reset: moving to HEAD~1 def9876 HEAD@{1}: commit: second abc4309 HEAD@{2}: commit (initial): initial
Look at `HEAD@{1}`: that is the commit I just lost, tagged "commit: second". The `HEAD@{0}` line is the reset itself, moving the branch back.
3

Recover the lost commit by creating a branch that points at the reflog entry. The commit is back on a named branch, safe to inspect or continue working.

git branch recovered HEAD@{1} git branch

Before you run it, say out loud what it will print. Then open the answer.

What it prints
main recovered
`recovered` now holds the lost commit while `main` sits at the old one. Inspect it with `git log recovered`, then delete the branch if it turned out to be junk.

Data Flow

The reflog records every HEAD movement, so even unreachable commits can be found and restored until they expire.
1 Move HEAD with a reset or checkout
↓
2 git records the move in the reflog
↓
3 The old position stays referenced
↓
4 Copy the hash to restore it
↓
5 Branch there to bring the work back
Why this works
Letting git clean up

The reflog keeps commits alive, but it also has an expiration. After the expiry date git is free to garbage-collect the unreachable ones. You can reach into that cleanup with git gc, but honestly you rarely need to. The healthy habit is simple: check the reflog before you trust that something is gone, and check it before you run a destructive reset.

When you have a choice

Reflog vs history

git log and the reflog are not the same thing, and confusing them costs people their work:

  • git log shows only commits reachable from your branches.
  • The reflog shows every move HEAD ever made, on this machine, including unreachable commits.

A dangling commit, one no branch points at, is findable in the reflog for a while, then git's normal cleanup eventually drops it. That window is usually 30 days, which is plenty of time to panic and recover.

Examples

Every HEAD movement, logged

git reflog

Unlike git log, which only sees committed history, the reflog records every time HEAD moved, commits, resets, checkouts, picks, rebases. Even a commit you reset away stays visible here, labeled with a new HEAD@{n} index. This is why git is recoverable in the first place.

Chase a lost branch

git reflog --no-abbrev --date=iso
git branch recovered <hash>

When you reset away a branch tip, the commits are not truly gone, they are still pointed to by an old HEAD@{n} entry. Copy that hash and create a branch there to pull the work back. I recovered an afternoon of work this way and never trusted a --hard reset without a reflog glance since.

Understand the index numbers

HEAD@{0}  # the very latest HEAD position
HEAD@{1}  # where HEAD was before the last move
HEAD@{2}  # two moves ago

The number is how many steps back in the reflog you are looking, not a commit number. The same commit can appear under several indexes as you move around. When in doubt, read the dates with --date=iso and match the entry to the moment you think you made the lost commit.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Git that checks its own work
Previous Lesson
Git that checks its own work