Introduction
The reflog records every change to HEAD and to each branch tip on your local machine. It is local, per-clone, and not pushed. Almost any "lost" commit can be rescued through it.
Viewing
git reflog # HEAD reflog
git reflog show main # main's reflog
git reflog --date=iso
git log -g --oneline # log walk through reflog
Each entry has a sequence (HEAD@{0}, HEAD@{1}, ...), an action (commit, reset, merge, rebase, ...), and a target SHA.
Recovering a lost commit
git reflog
# 9f8a1c2 HEAD@{0}: reset: moving to HEAD~3
# a1b2c3d HEAD@{1}: commit: Important work
git switch -c rescued a1b2c3d
Or directly:
git reset --hard HEAD@{1}
Time-based syntax
git show HEAD@{2.hours.ago}
git diff main@{yesterday} main
Git interprets @{...} as either a count or a date.
Reflog expiration
By default reachable reflog entries expire after 90 days, and unreachable ones after 30:
git config gc.reflogExpire 90.days
git config gc.reflogExpireUnreachable 30.days
Until expiration, even hard-reset commits remain recoverable.
Per-ref reflogs
Each branch has its own reflog at .git/logs/refs/heads/<name>. Stash also has one (refs/stash):
git reflog show stash
Pruning the reflog
git reflog expire --expire=now --all
git gc --prune=now
Use only if you need to permanently delete data; this removes the safety net.
Reflog vs git log
git log walks the commit graph by parent pointers; the reflog walks recorded movements of a ref. After a force-reset, git log no longer shows the abandoned commits, but the reflog still does.
Per-ref reflog inspection
Each ref keeps its own reflog. Inspect a specific branch's reflog to see how its tip moved:
git reflog show feature/login
git log -g feature/login --oneline
cat .git/logs/refs/heads/feature/login
Useful when investigating "who moved this branch?" on a local clone. The reflog file format is one line per change with old SHA, new SHA, committer, timestamp, and a textual message. Combined with git blame on the file, it gives a complete local audit trail; remember reflogs are not pushed, so the trail covers your machine only.
Common mistakes
Forgetting the reflog exists in a panic and re-doing hours of work that was easily recoverable. Always check git reflog first. Pushing during recovery and assuming the reflog is on the server; it is not, only your local clone has it. Running git gc --prune=now on a "clean up" instinct and destroying the safety net for any unreferenced commit. And finally, treating reflog entries as forever; long-deleted refs do age out. Tag or branch anything you want to keep before 30 days pass.