TechLead
Lesson 8 of 9
5 min read
Advanced Git

Reflog & Recovery

Use Git's reflog to recover lost commits, branches, and undo almost any mistake.

Understanding Reflog

Reflog (reference log) records when branch tips and HEAD change. It's your safety net for recovering from almost any Git mistake.

Viewing Reflog

# View HEAD reflog
git reflog

# View specific branch reflog
git reflog show main

# View with timestamps
git reflog --date=relative

# View with full commit info
git reflog --format=fuller

# View reflog for specific ref
git reflog show stash

Reflog Output

abc1234 HEAD@{0}: commit: Add new feature
def5678 HEAD@{1}: checkout: moving from main to feature
ghi9012 HEAD@{2}: reset: moving to HEAD~3
jkl3456 HEAD@{3}: commit: Previous work
mno7890 HEAD@{4}: merge feature: Fast-forward

Recovering Lost Commits

# After accidental reset
git reset --hard HEAD~3

# Find lost commits
git reflog
# Find: abc1234 HEAD@{1}: commit: Important work

# Recover
git reset --hard abc1234

# Or create new branch with lost commit
git branch recovered abc1234

Recovering Deleted Branch

# Accidentally deleted branch
git branch -D feature-branch

# Find the last commit
git reflog | grep feature-branch
# Or: git reflog | grep checkout.*feature

# Recreate branch
git branch feature-branch abc1234

Undoing a Bad Rebase

# After disastrous rebase
git rebase main
# Creates mess...

# Find pre-rebase state
git reflog
# Look for: HEAD@{5}: rebase started

# Reset to before rebase
git reset --hard HEAD@{5}

# Or use ORIG_HEAD (set before rebase)
git reset --hard ORIG_HEAD

Recovering Stash

# Accidentally dropped stash
git stash drop

# Find in reflog
git fsck --unreachable | grep commit

# Or search stash reflog
git reflog show stash

# Recover stash
git stash apply abc1234

Finding Lost Work

# Find all unreachable commits
git fsck --lost-found

# Commits are in .git/lost-found/commit/

# Search for specific content
git log --all --full-history -- "**/deleted-file.js"

# Search commit messages
git log --all --oneline | grep "keyword"

# Search in reflog
git reflog | grep "keyword"

Recovery Scenarios

# Scenario 1: Recover from bad merge
git reflog
git reset --hard HEAD@{1}

# Scenario 2: Recover amended commit
git reflog
# Old commit is HEAD@{1}
git branch recovered-original HEAD@{1}

# Scenario 3: Recover from reset --hard
git reflog
git reset --hard HEAD@{n}  # n = steps back

# Scenario 4: Recover file version
git checkout HEAD@{5} -- path/to/file.js

Reflog Expiration

# Default: 90 days for reachable, 30 for unreachable

# View expiration settings
git config gc.reflogExpire
git config gc.reflogExpireUnreachable

# Change expiration
git config gc.reflogExpire "180 days"
git config gc.reflogExpireUnreachable "90 days"

# Expire old entries manually
git reflog expire --expire=90.days.ago --all

# Never expire (not recommended)
git config gc.reflogExpire never

ORIG_HEAD and Other Refs

# ORIG_HEAD - set before dangerous operations
git reset --hard ORIG_HEAD

# MERGE_HEAD - during merge
cat .git/MERGE_HEAD

# FETCH_HEAD - last fetch
git log FETCH_HEAD

# CHERRY_PICK_HEAD - during cherry-pick
cat .git/CHERRY_PICK_HEAD

Preventive Measures

# Create backup branch before risky operations
git branch backup

# Use --dry-run when available
git clean -n  # Instead of git clean -f

# Check what will be affected
git log HEAD..origin/main  # Before pull
git log origin/main..HEAD  # Before push

# Enable rerere for conflict resolution memory
git config rerere.enabled true

When Reflog Can't Help

  • Uncommitted changes lost with reset --hard
  • Reflog entries expired (after gc)
  • Working with bare repositories
  • Files never staged or committed

Best Practices

  • Commit often, even WIP commits
  • Create branches before experiments
  • Know your reflog before doing destructive operations
  • Consider longer reflog expiration for important repos

Continue Learning