Recovering Lost Work with reflog
Reviewed & published by Brayan K
A bad git reset or a force-deleted branch feels like a disaster — until you learn the reflog. By the end of this lesson you'll be able to look up exactly where your code was before any mistake and bring it straight back.
Part of the free Git course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
What You'll Learn
- Read the reflog — Git's local diary of every place HEAD has been
- Recover commits wiped out by an accidental git reset --hard
- Understand HEAD@{n} reflog references vs HEAD~n history references
- Rebuild a branch you force-deleted with git branch -D
- Know that the reflog is local-only and time-limited
- Use git log -g to view reflog entries with full commit details
1️⃣ What the reflog Records
The reflog (reference log) is a local diary of every position HEAD has held. Every commit, reset, checkout, merge, and rebase adds an entry. Crucially, it remembers commits even after no branch points at them — which is what makes it a lifesaver. Each line reads <hash> HEAD@{n}: <move>, with HEAD@{0} being right now.
# git reflog is your safety net. It records EVERY position HEAD has held —
# every commit, reset, checkout, merge, and rebase — as a local diary.
# Even commits that no branch points at anymore still show up here.
# Show the reflog (newest move at the top)
git reflog
# Each line is: <hash> HEAD@{n}: <what moved HEAD there>
# HEAD@{0} is where you are now
# HEAD@{1} is where HEAD was one move ago, and so on2️⃣ The Disaster: a Bad Hard Reset
A git reset --hard HEAD~2 moves your branch back two commits and discards the working changes. It looks like the newer commits are gone — git log can't see them. But they're only unreferenced, not deleted, and the reflog logged the reset itself plus the tip you left behind.
# Scenario: you ran a hard reset and wiped two good commits by mistake.
git reset --hard HEAD~2 # 😱 "First commit" is all that's left now
git log --oneline # the two newer commits seem to be gone
# DON'T PANIC. The commits aren't deleted — they're just unreferenced.
# The reflog still remembers exactly where HEAD was before the reset.
git reflog
# Notice the reset itself is logged at HEAD@{0}, and the commit you
# want back is sitting right there at HEAD@{1}.3️⃣ The Rescue
Recovery is just pointing your branch back at the lost commit. Use the hash you read from the reflog, or the HEAD@{n} reference — they resolve to the same commit. git reset --hard moves the branch; git branch recovered <hash> rescues the work onto a new branch without disturbing where you are.
# Now recover. Point your branch back at the lost tip using either the
# hash or the reflog reference — they mean the same commit here.
git reset --hard HEAD@{1} # or: git reset --hard 12c3f59
git log --oneline # all three commits are back ✅
# Prefer to keep your current state and just peek? Create a branch instead:
git branch recovered 12c3f59 # rescue the work onto a fresh branchYour turn. Recover after a bad reset by reading the reflog and pointing the branch back. Fill in the two blanks.
# 🎯 YOUR TURN — replace each ___ then run it in a throwaway repo.
# Goal: recover after a bad reset.
# 1) Show the diary of where HEAD has been
git ___ # 👉 the command that prints the reflog
# 2) Read the line for the commit you want back, then move the branch to it
git reset --hard ___ # 👉 e.g. HEAD@{1} or the commit's hash
# 3) Confirm the lost commits are back
git log --oneline
# ✅ Expected: git log --oneline lists the commits you thought were gone.4️⃣ Recovering a Deleted Branch
Even a force-delete is recoverable. git branch -D feature-login prints (was 9a8b7c6) — that's the tip you discarded. Rebuild the branch with git branch feature-login 9a8b7c6. If you've already lost the hash, the reflog still has it.
# Recovering a force-deleted branch.
git branch -D feature-login # Git prints: Deleted branch feature-login (was 9a8b7c6).
# That "(was 9a8b7c6)" is the gift — it's the tip you just threw away.
# The reflog keeps it too, so you can rebuild the branch at that commit:
git branch feature-login 9a8b7c6
# Lost the hash already? The reflog still has it:
git reflog | grep feature-loginCommon Errors (and the fix)
- "fatal: ambiguous argument 'HEAD@{1}'": your shell may be eating the braces — wrap the reference in quotes: git reset --hard "HEAD@{1}".
- Confusing HEAD@{1} with HEAD~1: the first means "one reflog move ago"; the second means "one commit back in history". They are usually different commits.
- Reflog looks empty in a fresh clone: that's expected — the reflog is local and isn't transferred by clone. It starts recording from your first action in that copy.
- "unknown revision" when recovering an old commit: the entry may have been pruned by git gc. Recover promptly; entries expire (about 30–90 days by default).
Pro Tips
- 💡 Before any risky reset or rebase: note the current hash (or make a backup branch) so recovery is trivial.
- 💡 Per-branch reflog: git reflog show main shows just where main has moved.
- 💡 See details: git log -g --oneline walks the reflog with commit info attached.
- 💡 Truly orphaned objects: git fsck --lost-found can surface dangling commits the reflog missed.
📋 Quick Reference
| Command | Purpose |
|---|---|
| git reflog | Show HEAD's full movement history |
| git reflog show main | Reflog for one branch |
| git reset --hard HEAD@{1} | Move branch to a reflog position |
| git branch name <hash> | Rebuild a deleted branch at a hash |
| git log -g --oneline | Walk the reflog with commit details |
| git fsck --lost-found | Find dangling commits |
Mini-Challenge: Break It, Then Save It
No commands given this time — just the plan. Deliberately lose some commits and bring them all back using only the reflog.
# 🎯 MINI-CHALLENGE: break it, then save it.
# No commands given — just the plan. Run each step in a throwaway repo.
#
# 1. Make three commits on main (any small files)
# 2. Run "git reset --hard HEAD~2" to "lose" two of them
# 3. Open the reflog and find the hash of the newest commit
# 4. Recover by resetting hard back to that hash (or its HEAD@{n})
# 5. Confirm with "git log --oneline" that all three commits returned
#
# ✅ Expected: after recovery, git log --oneline shows all three commits.
# your commands here🎉 Lesson Complete!
- ✅ The reflog is a local diary of every place HEAD has pointed
- ✅ A bad reset --hard only unreferences commits — the reflog still has them
- ✅ Recover with git reset --hard HEAD@{n} or the commit hash
- ✅ Rebuild a force-deleted branch with git branch name <hash>
- ✅ The reflog is local-only and entries expire — recover promptly
Practice quiz
What does git reflog record?
- Every commit anyone ever pushed
- The remote branch history
- A local log of where HEAD (and branch tips) have pointed over time
- Only merge commits
Answer: A local log of where HEAD (and branch tips) have pointed over time. The reflog is a local diary of every position HEAD has held — commits, resets, checkouts, merges, rebases.
After 'git reset --hard HEAD~2', how do you find the lost commits?
- git reflog — the old tip still appears as HEAD@{1}
- They are gone forever
- git fsck only
- Re-clone the repo
Answer: git reflog — the old tip still appears as HEAD@{1}. The reset is itself logged, and the previous HEAD position remains in the reflog as HEAD@{1}.
What does the notation HEAD@{1} mean?
- The commit one before the current branch tip
- The first commit in the repo
- The remote HEAD
- Where HEAD pointed one reflog move ago
Answer: Where HEAD pointed one reflog move ago. HEAD@{n} is a reflog reference: where HEAD was n moves ago, not n commits back in history.
How do you restore your branch to a lost commit shown in the reflog?
- git reflog restore
- git reset --hard <hash> (or HEAD@{n})
- git pull
- git commit --amend
Answer: git reset --hard <hash> (or HEAD@{n}). Once you read the hash from the reflog, git reset --hard <hash> moves the branch back to it.
Is the reflog shared with collaborators when you push?
- No, the reflog is purely local to your clone
- Yes, it is pushed automatically
- Only with --all
- Only on the default branch
Answer: No, the reflog is purely local to your clone. The reflog lives in .git/logs and is never transferred by push, fetch, or clone.
You deleted a branch with -D before merging. Can you get it back?
- No, force-delete is permanent
- Only if you had pushed it
- Yes — the reflog shows the deleted tip's hash so you can recreate the branch
- Only with git stash
Answer: Yes — the reflog shows the deleted tip's hash so you can recreate the branch. git branch -D prints '(was <hash>)' and the reflog keeps that hash, so git branch name <hash> rebuilds it.
How long do reflog entries typically last by default?
- Forever
- About 90 days for reachable, 30 days for unreachable entries before gc prunes them
- 1 day
- Until the next commit
Answer: About 90 days for reachable, 30 days for unreachable entries before gc prunes them. gc.reflogExpire defaults to 90 days (30 for unreachable), so recover lost work promptly.
Which command recreates a deleted branch at a recovered hash?
- git reflog feature
- git checkout --orphan
- git restore feature
- git branch feature <hash>
Answer: git branch feature <hash>. git branch <name> <hash> creates a new branch pointing at the recovered commit.
What is the difference between git log and git reflog?
- Nothing
- git log walks commit ancestry; git reflog lists HEAD's movement history, including commits no longer in any branch
- reflog is remote-only
- log is local-only
Answer: git log walks commit ancestry; git reflog lists HEAD's movement history, including commits no longer in any branch. git log follows parents of reachable commits; reflog can reach 'dangling' commits a reset orphaned.
Which flag shows reflog-style entries through git log instead?
- git log --reflog
- git log --orphans
- git log -g (or --walk-reflogs)
- git log --recover
Answer: git log -g (or --walk-reflogs). git log -g walks the reflog, combining commit details with reflog ordering.
Continue this course
- Previous: Cherry-Picking Commits
- Next: Finding Who Changed What with git blame — Trace each line to its commit with git blame and the pickaxe (log -S)
- Quick reference: Git cheat sheet › Undoing
Frequently asked questions
Is git reflog the same as git log?
No. git log walks the commit ancestry that branches and tags can reach. git reflog is a local diary of every place HEAD (and each branch tip) has pointed over time — including commits that no branch references anymore after a reset or rebase. That's exactly why reflog can rescue work that git log can no longer see.
Can other people see my reflog?
No. The reflog lives in your .git/logs directory and is purely local. It is never copied by push, fetch, or clone, so a fresh clone of your project has an empty reflog. It only reflects what you personally did in your own working copy.
How long do I have to recover lost commits?
By default, reachable reflog entries are kept about 90 days and unreachable ones about 30 days before git gc may prune them (gc.reflogExpire / gc.reflogExpireUnreachable). In practice that's plenty, but treat reflog recovery as something to do soon rather than months later.
What does HEAD@{1} mean exactly?
It's a reflog reference: 'where HEAD pointed one move ago'. HEAD@{0} is now, HEAD@{1} is the move before that, and so on. This counts reflog moves (commits, resets, checkouts), not commits in history — so HEAD@{1} is not the same as HEAD~1.
I force-deleted a branch with -D. Is it really gone?
Usually not. git branch -D prints '(was <hash>)' with the tip it removed, and that commit stays in the reflog and object store for a while. Recreate the branch with git branch <name> <hash>. If you lost the hash, search the reflog: git reflog | grep <name>.