Reflog and recovering lost work

Git · Advanced · 10 min

It turns 'I destroyed my work' into a two-minute fix, which makes you braver with history rewriting.

Every time HEAD or a branch moves (commit, reset, rebase, checkout, merge, amend, pull), Git appends an entry to the reflog. It's local only, never pushed, and it is your undo history.

git reflog shows HEAD's log, newest first:

9d2c4e1 HEAD@{0}: reset: moving to HEAD~3
5b7a0f3 HEAD@{1}: commit: Add export button
...

HEAD@{1} means "where HEAD was one move ago". git reflog show feature shows a branch's own log, and time-based forms such as main@{yesterday} work too.

Recovery recipes:

  • Undo a bad reset or rebase: find the entry from before it, then git reset --hard HEAD@{4} (or the hash). After a rebase, ORIG_HEAD also points at the pre-rebase tip.
  • Restore a deleted branch: find its last commit in the reflog (git branch -D prints the hash too) and git branch feature <hash>.
  • Rescue commits made in detached HEAD: they are in HEAD's reflog; create a branch at them.

Commits removed from all branches are unreachable but not deleted immediately. Reflog entries expire after 90 days by default (30 days for entries no longer reachable), and git gc then removes the objects. If even the reflog is gone, git fsck --lost-found can find dangling commits.

The limit: the reflog tracks commits. Changes you never committed or stashed, then wiped with reset --hard or restore, are not in it. Commit often and you can always get back.

Example

git reset --hard HEAD~3          # oops, those commits mattered
git reflog -5
# 9d2c4e1 HEAD@{0}: reset: moving to HEAD~3
# 5b7a0f3 HEAD@{1}: commit: Add export button
git reset --hard HEAD@{1}        # back to before the reset

git branch -D experiment         # Deleted branch experiment (was 41c8e2a).
git branch experiment 41c8e2a    # restored

git rebase origin/main           # went wrong?
git reset --hard ORIG_HEAD       # tip before the rebase

Remember

  • Every HEAD/branch movement is logged locally in the reflog
  • Recover with git reset --hard HEAD@{n} or git branch name <hash>
  • Unreachable commits survive about 30-90 days before gc
  • Uncommitted work is not in the reflog

Watch out for

  • Expecting the reflog to exist on a fresh clone — it's local to each repository.

Check yourself

  1. You hard-reset away three commits an hour ago. Can you get them back?
  2. Which of these can the reflog NOT recover?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: git-scm.com/docs/git-reflog