git reflog may be the most underrated command in Git. It does not create commits or move branches. It quietly records one thing: where your references used to point.
Most people meet it after a disaster. A reset --hard wipes out an afternoon of work. A deleted branch takes days of commits with it. Git suddenly feels like a demolition machine, and reflog is the undo key hidden behind a side door.
It remembers references, not files
Let's clear up a common misconception: reflog is not a file backup. It records the movement of HEAD and branch references. The commit objects are still sitting in Git's object database. What was lost was the name pointing at them.
Think of reflog as a ship's log:
- where you departed from;
- which commit you docked at;
- which rebase, merge, or reset changed the route;
- and the command used at the time.
Read the full log with:
git reflog --date=iso
The output looks like this:
a1f9e2d HEAD@{2026-11-03 09:42:17 +0800}: reset: moving to HEAD~2
7c3d0ab HEAD@{2026-11-03 09:39:02 +0800}: commit: feat: add reading progress
Every line is a point in time you can recover. HEAD@{n} is not an abstract number. It is a real path back.
Recover a deleted branch
Suppose you delete feature/search while tidying up, then realize it was never merged.
Find where it last pointed:
git reflog
Then create a new branch at that commit:
git branch feature/search HEAD@{4}
If the branch name is all you need, you can restore it in place. As long as the commit object has not been garbage-collected, the deletion was only a renaming.
A second chance after reset
git reset --hard sounds dangerous, but reflog often turns it into a reversible operation.
git reflog
# find the commit before the reset
git branch rescue a1f9e2d
Do not rush to move the original branch back. Create a rescue branch first, verify the content, then bring across only what you need with cherry-pick, reset, or a new commit. Undo is not time travel. It is retrieving the right pieces from the past.
It is not a backup strategy
reflog is useful, but it has boundaries:
- by default it lives only on your machine and is not pushed;
- entries expire according to
gc.reflogExpire, usually around 90 days; - it cannot recover untracked files that were deleted;
- once objects are garbage-collected, the path disappears too.
So it is not a backup. It is a safety buffer that Git leaves open for you. Important work still belongs on a remote, in a backup, or at a deliberate checkpoint.
Over time I stopped using git reflog only for rescues. It became a way to see how I move: which operations were necessary, and which resets were covering up a commit that should have been clearer.
A timeline does not lie. Once you can read it, Git stops being a pile of commands and becomes a map you can look back on.