Git reflog: recover anything you thought you lost
Git's reflog is the safety net most engineers do not know they have. Every time HEAD moves — commit, checkout, reset, rebase, merge — git records it in the reflog. That means even commits that appear to be gone — deleted branches, force-pushed history, botched rebases — are almost always recoverable as long as you have not run git gc recently. Here are the recovery procedures for the most common disasters.
What the reflog actually is
# Show the reflog
git reflog
# Output:
# a3f9d21 (HEAD -> main) HEAD@{0}: commit: fix: null check in payment
# b88c012 HEAD@{1}: checkout: moving from feature to main
# c1d4f33 HEAD@{2}: commit: feat: add dark mode
# d02e891 HEAD@{3}: rebase (finish): returning to refs/heads/feature
# e5a3b44 HEAD@{4}: reset: moving to HEAD~1
# f9901ac HEAD@{5}: commit: feat: initial dark mode scaffolding
Each line is a state HEAD was in. The HEAD@{N} syntax lets you reference any of these states directly.
Scenario 1: Accidentally deleted a branch
# You accidentally deleted a branch
git branch -D feature/payments
# "Deleted branch feature/payments (was c1d4f33)"
# Step 1: Find the last commit on that branch in the reflog
git reflog | grep feature/payments
# c1d4f33 HEAD@{5}: checkout: moving from feature/payments to main
# Step 2: Recreate the branch at that commit
git branch feature/payments c1d4f33
# Done — your branch is back
Scenario 2: Botched a rebase
# Your rebase went wrong and your branch history is a mess
# First, abort if rebase is in progress
git rebase --abort
# Find where your branch was before the rebase
git reflog | head -20
# Look for the commit just before "rebase (start)"
# Reset to that commit
git reset --hard HEAD@{7}
# Replace 7 with whatever index shows the state before rebase started
Scenario 3: Undid a commit with git reset --hard
# You ran: git reset --hard HEAD~3 and now those commits are gone from your branch
# The commits still exist in git — they are just unreachable
# Find the lost commits
git reflog
# HEAD@{1} was the commit before your reset
# Look for the commit hash that had your work
# Restore by resetting to that commit
git reset --hard HEAD@{1}
# Or cherry-pick just the specific commit
git cherry-pick a3f9d21
Scenario 4: Recovered from force push
# Someone force-pushed to a shared branch and overwrote your commits
# Your local reflog still has the old commits
# Find the commit before the force push (look for the push/fetch entry)
git reflog show origin/main | head -10
# origin/main@{0}: forced-update: refactored login (force)
# origin/main@{1}: update: feat: add payment processing ← this was your work
# Get the hash of your lost work
git show origin/main@{1}
# Create a branch from it to recover
git branch recovery/my-work origin/main@{1}
Scenario 5: Dropped a stash
# git stash drop removed a stash with important work
# Stashes are stored as commits — they show up in the reflog
# Find dropped stashes (they appear as stash@{N} entries)
git fsck --lost-found | grep commit
# Or search reflog for stash entries
git log --all --oneline | head -30 # look for dangling commits
# Apply a recovered stash
git stash apply COMMIT_HASH
Scenario 6: Wrong branch for a commit
You committed to main when you meant to commit to a feature branch:
# You committed feat: dark mode to main instead of feature/dark-mode
git log --oneline main | head -3
# a3f9d21 feat: dark mode (this should not be on main)
# b88c012 fix: previous fix
# Step 1: Get the commit hash
COMMIT=a3f9d21
# Step 2: Put it on the right branch
git checkout feature/dark-mode
git cherry-pick $COMMIT
# Step 3: Remove it from main
git checkout main
git reset --hard HEAD~1 # removes the last commit from main
# Reflog lets you undo step 3 if you made a mistake
git reflog
git reset --hard HEAD@{1} # undo the reset if needed
Reflog expiry
The reflog is not permanent. By default, entries expire after 90 days (30 days for unreachable commits). Running git gc can prune them earlier. The window for recovery exists but is not infinite — if you discover a disaster weeks later, act quickly.
# See how long your reflogs are kept
git config gc.reflogExpire # default: 90 days
git config gc.reflogExpireUnreachable # default: 30 days
# Extend if you are worried about a specific recovery
git config gc.reflogExpire "180 days"
Reflog is the reason I tell engineers: do not panic after a git mistake. The data is almost certainly still there. Take a breath, open the reflog, find where you were, and reset to it. A disaster that felt permanent takes five minutes to reverse.