Have you ever run:
git reset --hard HEAD~1
…and watched your latest commit disappear? Or rebased the wrong branch? Or force pushed and thought — that's it, it's gone.
I've been there. Most developers have. And almost every time, the work wasn't actually gone — I just didn't know where to look.
That place is reflog. And once you know it exists, Git becomes a fundamentally less scary tool.
What Reflog Actually Is
Git keeps two types of history that most developers confuse.
git log shows your project history — the commits on your current branch in order. git reflog shows something different: the history of where your HEAD pointer has been. Every time you commit, checkout a branch, reset, rebase, merge, or amend — Git moves HEAD and reflog records that movement.
The critical difference: commits can disappear from git log after a reset or rebase. They never disappear from reflog until Git's garbage collector removes them weeks later.
Think of it this way:
- Commits = snapshots of your code
- Branch = a pointer to a commit
- HEAD = your active pointer
- Reflog = the diary of everywhere HEAD has moved
When things go wrong, you rewind the diary.
Why It Exists
Git gives you powerful history-rewriting tools — reset, rebase, commit --amend, cherry-pick. These are genuinely useful, but they can go sideways fast. Reflog is Git's local safety journal. A black box recorder for your repository. Even if you crash your branch, reflog almost always knows where you were before.
The key word is local. Reflog lives only on your machine. It is not pushed to GitHub. It won't help if your teammate force pushes a shared branch — but for your own mistakes, it's almost always the answer.
Reading Reflog Output
git reflog
Output looks like this:
a1b2c3d HEAD@{0}: commit: updated login form
d4e5f6g HEAD@{1}: checkout: moving from feature to main
h7i8j9k HEAD@{2}: commit: added login feature
abc1234 HEAD@{3}: reset: moving to HEAD~1
def5678 HEAD@{4}: commit: add payment logic
HEAD@{0} is where you are now. HEAD@{1} is one move ago. Each entry shows what happened — a commit, a checkout, a reset — and the hash of the commit HEAD was pointing to at that moment.
The entries you're looking for after a mistake are usually the ones just before a reset: or rebase line.
Recovering a Lost Commit
This is the scenario that sends most developers to Stack Overflow in a panic.
You ran git reset --hard HEAD~1. Your latest commit is gone from git log. Here's what you actually do:
Step 1 — Run reflog, don't touch anything else
git reflog
Find the commit just before the reset. It'll look something like:
abc1234 HEAD@{0}: reset: moving to HEAD~1
def5678 HEAD@{1}: commit: add payment logic ← this is what you want
Step 2 — Restore it
If you want the commit back immediately:
git reset --hard def5678
If you want to inspect it before committing to anything:
git checkout def5678
# Look around, verify it's what you need
git checkout -b recovery-branch # save it as a branch
That's it. The commit you thought was gone is back.
Recovering a Deleted Branch
git branch -D feature-x
Gone. Or so it seems.
git reflog
# Find the last commit you made on that branch
# e.g. c9d8e7f HEAD@{3}: commit: add feature x final
git branch feature-x c9d8e7f
Branch restored. The commits were never actually deleted — just the pointer to them was removed.
Fixing a Bad Rebase
Rebase gone wrong is the scenario that turns reflog from "useful to know" into "genuinely life-saving." You rebased onto the wrong branch, squashed commits you needed, or ended up in a state you don't understand.
git reflog
Look for the entry just before rebase (start):
HEAD@{4}: commit: working state before rebase ← go here
HEAD@{3}: rebase (start): checkout main
HEAD@{2}: rebase (pick): ...
HEAD@{1}: rebase (finish): ...
HEAD@{0}: rebase (finish): returning to refs/heads/feature
Reset back to before it started:
git reset --hard HEAD@{4}
Branch is restored to exactly where it was before the rebase began. Nothing lost.
Using HEAD@{n} Directly
You don't always need the commit hash. You can reference reflog entries directly:
git reset --hard HEAD@{3}
This moves your branch back three HEAD movements. Useful when you're working quickly and the entry you want is easy to count. When you're unsure, use the hash — it's more explicit and harder to get wrong.
What Reflog Won't Save You From
Reflog is powerful but it has real limits. It won't help if:
- You deleted your entire
.gitfolder - The repo was freshly cloned after the history was destroyed
- Git's garbage collector already ran and removed the objects (happens after ~90 days by default, 30 days for unreachable commits)
- The changes were never committed in the first place
That last one is the most common trap. Reflog only tracks committed states. If you had uncommitted work when something went wrong — use git stash before doing anything risky, or commit to a throwaway branch. Uncommitted changes that get wiped by --hard are genuinely gone.
The First Time I Found This
Back in 2018, I was new to development — still finding my footing with Git, still treating every command like it might blow something up. I accidentally ran a hard reset and lost a commit I'd spent an hour on. I thought it was gone. I started re-writing it from scratch, frustrated and convinced I'd done something unrecoverable.
So I did what most of us did back then when we got stuck — I went straight to Stack Overflow. That was basically how we fixed things and learned new tricks in those days. While digging through a few answers, I came across someone mentioning git reflog.
I ran it, saw a list of recent HEAD movements, spotted the hash of my missing commit and said "there it is." Thirty seconds. I sat there genuinely stunned — that Git had been quietly keeping this diary the whole time and nobody had mentioned it.
That was the moment Git stopped feeling like a minefield. Knowing reflog existed changed how I used every other command — I stopped being cautious about resets and rebases because I knew there was always a way back.
A Real Moment This Saved Me Later
I was cleaning up a feature branch before a PR — squashing commits, rewriting messages, making everything look intentional. Somewhere in the middle of an interactive rebase I got confused about what I was editing, ended up squashing commits I needed separately, and the branch ended up in a state I couldn't cleanly explain.
I'd spent 40 minutes on the cleanup. I didn't want to redo it but I also couldn't ship the mess I'd created.
git reflog
Found HEAD@{6} — the entry just before I started the rebase. One command:
git reset --hard HEAD@{6}
Back to the clean starting state. I did the rebase again, more carefully this time, in about 15 minutes. The 40 minutes felt wasted but the recovery took 30 seconds.
Without reflog I would have started the branch over from scratch.
Your Recovery Workflow
When something breaks, run through this in order:
# 1. Stop. Don't run more commands.
# 2. See where HEAD has been
git reflog
# 3. Find the right entry — just before things went wrong
# 4. Inspect it first if unsure
git checkout <hash>
# 5. Reset back when you're confident
git reset --hard <hash>
And a habit worth building: before doing anything risky — a complex rebase, a reset, an amend on something important — run git reflog and note the current HEAD@{0} hash. If anything goes wrong, git reset --hard <that hash> brings you straight back.
Wrapping Up
Most developers only learn reflog after losing work. You now know it before disaster strikes.
It's not advanced magic. It's a diary that Git keeps automatically, in the background, on every repository. The only difference between developers who panic when something breaks and developers who don't is knowing it's there.
The next time something disappears — breathe, run git reflog, find the entry, reset. That's the whole thing.
Part of the Git series on Shakil Tech. The Git Rebase vs Merge post goes deeper on the scenarios where reflog becomes your safety net — interactive rebase, squashing, keeping history clean.
Top comments (0)