Git - Reflog & Recovery
Advanced
Git reflog is your safety netβit records every change to HEAD in your repository. When you think you've lost commits, reflog is usually your path to recovery. Understanding reflog can save you from Git disasters.
What is Git Reflog?
Reflog (reference log) maintains a history of when the tips of branches and other references were updated. It's like a time machine for your repository:
HEAD Movement History:
HEAD@{0} β Current position
HEAD@{1} β Previous position
HEAD@{2} β Position before that
HEAD@{3} β And so on...
Key characteristics:
- Local only: Not shared between repositories
- Time-limited: Entries expire (default 90 days)
- Branch-specific: Each branch has its own reflog
- Comprehensive: Records all HEAD movements
Viewing Reflog
Basic Reflog Commands
# Show reflog for current branch
git reflog
# Show reflog for specific branch
git reflog main
# Show reflog with dates
git reflog --date=iso
# Show reflog with relative dates
git reflog --date=relative
Example reflog output:
d4e5f6g (HEAD -> main) HEAD@{0}: commit: Add user authentication
c3d4e5f HEAD@{1}: pull: Fast-forward
b2c3d4e HEAD@{2}: reset: moving to HEAD~1
a1b2c3d HEAD@{3}: commit: Fix styling bug
e5f6g7h HEAD@{4}: checkout: moving from feature-branch to main
f6g7h8i HEAD@{5}: commit: Complete feature implementation
g7h8i9j HEAD@{6}: rebase finished: returning to refs/heads/feature-branch
Understanding Reflog Entries
Each reflog entry shows:
- Commit hash: Where HEAD was pointing
- Reference: HEAD@{n} notation
- Action: What command caused the change
- Message: Description of the action
Common reflog actions:
commit: New commit created
reset: HEAD moved with git reset
pull: Changes pulled from remote
merge: Branches merged
rebase: Interactive or regular rebase
checkout: Branch switched
cherry-pick: Commit cherry-picked
clone: Repository cloned
Recovery Scenarios
Scenario 1: Accidental Hard Reset
Problem:
# Accidentally destroyed last 3 commits
git reset --hard HEAD~3
Recovery:
# 1. Check reflog to find lost commits
git reflog
# Look for entry before the reset:
# a1b2c3d HEAD@{1}: commit: Important feature
# 2. Reset back to that commit
git reset --hard HEAD@{1}
# Or use the commit hash directly
git reset --hard a1b2c3d
Scenario 2: Lost Branch After Merge
Problem:
# Merged feature branch and deleted it
git merge feature-important
git branch -D feature-important
# Later realized you need the branch back
Recovery:
# 1. Find the branch in reflog
git reflog --all | grep feature-important
# 2. Recreate branch from reflog entry
git branch feature-important HEAD@{5}
# Or if you find the commit hash
git branch feature-important a1b2c3d
Scenario 3: Failed Rebase Recovery
Problem:
# Rebase went wrong, conflicts everywhere
git rebase main
# ... conflicts ...
git rebase --abort # But this doesn't restore everything
Recovery:
# 1. Check reflog for state before rebase
git reflog
# Look for: HEAD@{3}: rebase started
# Previous entry shows original state
# 2. Reset to pre-rebase state
git reset --hard HEAD@{4}
Advanced Reflog Usage
Filtering Reflog Entries
# Show only commits (exclude other actions)
git reflog --grep="commit"
# Show entries from specific timeframe
git reflog --since="2 hours ago"
git reflog --until="yesterday"
# Show entries with patch information
git reflog -p
Branch-Specific Reflogs
# Show reflog for specific branch
git reflog refs/heads/main
# Show reflog for remote tracking branch
git reflog refs/remotes/origin/main
# Show all reflog entries for all references
git reflog --all
Recovery Techniques
Interactive Recovery
# Use git log with reflog to see full history
git log --walk-reflogs --oneline
# Show unreachable commits
git fsck --unreachable
# Find specific content in lost commits
git log --all --full-history -S"lost content"
Creating Recovery Branches
Safe recovery approach:
# 1. Create recovery branch instead of resetting
git branch recovery-branch HEAD@{3}
# 2. Switch to recovery branch to examine
git switch recovery-branch
# 3. Check if this is what you want
git log --oneline -10
# 4. If correct, merge back or reset main
git switch main
git reset --hard recovery-branch
# 5. Clean up
git branch -d recovery-branch
Reflog Configuration
Expiration Settings
# Default settings (don't change unless necessary)
git config --global gc.reflogExpire 90.days
git config --global gc.reflogExpireUnreachable 30.days
# Check current settings
git config --get gc.reflogExpire
# Disable expiration (not recommended)
git config --global gc.reflogExpire never
Reflog for Worktrees
# Each worktree has separate reflog
git worktree add ../feature-worktree feature-branch
cd ../feature-worktree
git reflog # Shows reflog for this worktree
Emergency Recovery Procedures
Complete Disaster Recovery
When everything seems lost:
# 1. DON'T PANIC - Git rarely loses data
# 2. Check reflog first
git reflog --all
# 3. Look for unreachable objects
git fsck --full --unreachable
# 4. Find recent commits
git log --all --oneline --since="1 week ago"
# 5. Search for specific content
git grep -n "important function" $(git fsck --unreachable | grep commit | cut -d' ' -f3)
# 6. Create branches for suspicious commits
git branch maybe-important COMMIT_HASH
Reflog Repair
# If reflog is corrupted
git reflog expire --expire=now --all
git reflog --all
# Rebuild reflog from scratch (loses history)
rm -rf .git/logs/
git reflog expire --expire=now --all
Warning: Reflog repair commands can permanently delete recovery information. Only use as last resort.
Prevention is Better than Recovery
Safe Practices
- β Create backup branches before dangerous operations
- β
Use
git stash
for temporary work - β Push important branches to remote
- β Commit frequently, even with temporary messages
- β
Use
--dry-run
for destructive commands
Pre-operation backup:
# Before risky operations
git branch backup-$(date +%Y%m%d-%H%M%S)
# Or tag important states
git tag before-big-change
# Push backups to remote
git push origin backup-$(date +%Y%m%d-%H%M%S)
Monitoring Repository Health
# Regular repository checks
git fsck --full
git gc --prune=now
# Check for corruption
git verify-pack -v .git/objects/pack/*.idx
# Monitor reflog size
du -sh .git/logs/
Reflog Limitations
What Reflog Cannot Recover
- β Uncommitted changes (working directory)
- β Untracked files that were never added
- β Commits from other repositories
- β Expired reflog entries
- β Reflogs from deleted repositories
When Reflog Doesn't Help
Alternative recovery methods:
# File-level recovery
git show HEAD:filename > recovered-file.txt
# Search in all commits
git log --all --full-history -- filename
# Use file system backups
# Use IDE history features
# Check backup services (Time Machine, etc.)
Practical Recovery Examples
Example 1: Recover Deleted Commits
Step-by-step recovery:
# 1. Find the lost commits
git reflog --oneline | head -20
# 2. Identify the commit you want
# e.g., a1b2c3d HEAD@{5}: commit: Lost important work
# 3. Create recovery branch
git branch recovery a1b2c3d
# 4. Verify it's correct
git log recovery --oneline -5
# 5. Merge back if satisfied
git merge recovery
Example 2: Undo Bad Merge
# Bad merge happened
git reflog | grep merge
# Found: b2c3d4e HEAD@{2}: merge feature: Merge made by 'ort' strategy
# Go back to before merge
git reset --hard HEAD@{3}
# Verify state
git log --oneline -5
Summary
You now understand Git reflog and recovery:
- β Reflog records every HEAD movement locally
- β
git reflog
shows history of changes - β HEAD@{n} notation references historical states
- β Most "lost" commits can be recovered via reflog
- β Create backup branches before risky operations
- β Reflog has limitationsβprevention is better
- β Emergency procedures exist for disaster recovery
Next Steps
Now that you understand recovery, let's explore advanced Git operations like rebasing:
Practice Tip: Intentionally "break" a test repository and practice recovery techniques. Knowing reflog can save hours of lost work in real projects.