Lesson 14 of 30
"I think I just lost commits" almost never means they're gone. The reflog is Git's private log of every place HEAD has pointed — your actual safety net.
15 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
This topic is about judgment and practical tradeoffs more than a single right answer — a mock interview is the better way to test yourself on it.
Be interviewed on this →Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
The reflog is a log Git keeps for you, locally, of every place HEAD (and each branch) has pointed over time — every commit, checkout, reset, rebase, and branch deletion. It's easy to confuse with git log, but they track completely different things: git log walks commit history — the chain of parent pointers baked into the commits themselves, which is the same for anyone who clones the repo. The reflog tracks your HEAD's own movements — it's local-only, never pushed, never shared, and it's the record of what you personally did, not what the project's history says happened.
That distinction is exactly why the reflog is the recovery tool. A commit that becomes unreachable — after a reset --hard, an interactive rebase that dropped it, or a branch deletion — disappears from git log because nothing points to it anymore. But it isn't deleted from the object store, and the reflog still remembers that HEAD pointed at it a moment ago. As long as Git's garbage collector hasn't run (default: ~30 days for unreachable objects), you can point a branch back at it.
Say you're mid-cleanup and run the wrong reset — three real commits, gone from git log:
$ git log --oneline -3
c4f1a90 add validation to signup form
9b2e77d fix email regex
7a1d203 wire up submit handler
$ git reset --hard HEAD~3
HEAD is now at 3f8e001 initial commit
git log now shows nothing after 3f8e001 — those three commits look gone. Check the reflog instead:
$ git reflog
3f8e001 (HEAD -> main) HEAD@{0}: reset: moving to HEAD~3
c4f1a90 HEAD@{1}: commit: add validation to signup form
9b2e77d HEAD@{2}: commit: fix email regex
7a1d203 HEAD@{3}: commit: wire up submit handler
3f8e001 HEAD@{4}: checkout: moving from main to main
HEAD@{1} is exactly where you were right before the reset — c4f1a90, with all three commits still attached behind it (each commit's parent pointer is untouched; only the branch label moved). Point main back at it:
$ git reset --hard c4f1a90
HEAD is now at c4f1a90 add validation to signup form
$ git log --oneline -3
c4f1a90 add validation to signup form
9b2e77d fix email regex
7a1d203 wire up submit handler
All three are back, with their original hashes intact — they were never actually destroyed, just temporarily unreachable from any branch. The same trick recovers a commit after a rebase that squashed away something you wanted, or even a deleted branch: git reflog still shows HEAD@{N}: checkout: moving from <deleted-branch> to main with the last commit hash that branch pointed to, right before it vanished.
A branch history: commit A, then B, then C. HEAD and main both point at C, the tip — every commit is reachable.
git gc, which runs automatically sometimes and can be triggered manually), unreachable commits, their trees, and their blobs are still sitting in .git/objects — the reflog is just the map that tells you which hash to point back at.The reflog only clicks once you've internalized that a branch is nothing but a movable pointer to a commit hash — the same idea from the mental-model concept. Deleting a branch, resetting one, or rebasing one never destroys the commits it pointed to; it just moves or removes the pointer. The reflog is the record of every pointer move you made, which is exactly what lets you put the pointer back.