Git Recovery Magic: Reflog, Reset Recovery, and Cherry-Picking
- 6 git
Introduction
In this article we will explore Git’s most powerful recovery features that can save your day when things go wrong. If you’ve ever lost commits after a bad rebase, accidentally deleted a branch, or needed to grab just one specific commit from another branch, you know the panic. But Git never truly forgets - it’s just a matter of knowing where to look.
Git’s reflog is like a time machine for your repository. Every action you take is recorded, and with the right commands, you can recover almost anything. We’ll also dive into cherry-picking, which lets you surgically extract specific commits and apply them wherever you need them.
By the end of this article, you’ll never fear Git operations again. You’ll know that whatever happens, there’s almost always a way to get your work back.
Understanding the Reflog
The reflog (reference log) is Git’s safety net. It records every change to HEAD and branch tips in your local repository. Think of it as Git’s undo history - but way more powerful.
Let’s start by looking at what’s in your reflog:
git reflog
# or for more detail
git reflog show HEAD
You’ll see something like this:
3f7a8b9 (HEAD -> main) HEAD@{0}: commit: Add new feature
8d4c2e1 HEAD@{1}: rebase -i (finish): returning to refs/heads/main
8d4c2e1 HEAD@{2}: rebase -i (pick): Update documentation
a5b9c3d HEAD@{3}: rebase -i (squash): Fix bug
e2f1d4c HEAD@{4}: rebase -i (start): checkout origin/main
7c9e3a2 HEAD@{5}: commit: Work in progress
Each entry shows:
- The commit SHA
- The reflog entry reference (HEAD@{n})
- The action that was performed
- The commit message or operation details
The beautiful thing? These entries persist for 90 days by default (30 days for unreachable commits), giving you plenty of time to recover from mistakes.
Recovering from a Bad Rebase
Let’s say you’re rebasing and things go horribly wrong. Maybe you accidentally dropped important commits or resolved conflicts incorrectly. Don’t panic!
Scenario: Messed up interactive rebase
# You did an interactive rebase
git rebase -i HEAD~5
# You accidentally deleted important commits or messed up the history
# Now your branch is broken
Recovery using reflog:
# First, check where you were before the rebase
git reflog
# Find the entry before "rebase -i (start)"
# Let's say it's HEAD@{5}
# Option 1: Reset to before the rebase
git reset --hard HEAD@{5}
# Option 2: If you want to be more careful, create a backup branch first
git branch backup-before-reset
git reset --hard HEAD@{5}
Pro tip: Always check what you’re resetting to first:
# See what's at that reflog entry
git show HEAD@{5}
# See the full log from that point
git log HEAD@{5} --oneline -10
Recovering Deleted Commits (After git reset)
Accidentally ran git reset --hard and lost commits? They’re not gone, just unreferenced. Here’s how to get them back:
Scenario: Accidental hard reset
# You had important work
git log --oneline
# abc123 Important feature
# def456 Critical bugfix
# ghi789 Previous work
# Then you accidentally reset
git reset --hard HEAD~2
# Oh no! Your important feature and bugfix are gone!
Recovery process:
# Step 1: Find the lost commits in reflog
git reflog
# You'll see something like:
# ghi789 HEAD@{0}: reset: moving to HEAD~2
# abc123 HEAD@{1}: commit: Important feature
# def456 HEAD@{2}: commit: Critical bugfix
# Step 2: Recover to the lost commit
git reset --hard HEAD@{1}
# or use the SHA directly
git reset --hard abc123
# Alternative: Cherry-pick specific commits if you don't want to reset
git cherry-pick abc123
git cherry-pick def456
Creating a recovery branch: Sometimes you want to explore the lost commits without affecting your current branch:
# Create a new branch from the lost commit
git branch recovery-branch abc123
# Switch to it and check
git checkout recovery-branch
git log --oneline
# If everything looks good, merge it back
git checkout main
git merge recovery-branch
Recovering Deleted Branches
Deleted a branch by mistake? As long as it wasn’t deleted on the remote and force-pushed, you can recover it locally.
Scenario: Accidental branch deletion
# You had a feature branch
git branch
# * main
# feature-awesome
# bugfix-critical
# Accidentally deleted it
git branch -D feature-awesome
# Deleted branch feature-awesome (was 5a3f8c9).
Recovery methods:
Method 1: If you see the SHA in the deletion message
# Git tells you the SHA when deleting
# Just recreate the branch from that commit
git branch feature-awesome 5a3f8c9
# Or checkout and recreate
git checkout -b feature-awesome 5a3f8c9
Method 2: Using reflog to find the branch
# Search reflog for the branch name
git reflog show --all | grep feature-awesome
# Or look for commits from that branch
git reflog --all
# Once you find the last commit SHA
git checkout -b feature-awesome-recovered <sha>
Method 3: If you recently checked out the branch
# Git tracks branch checkouts
git reflog | grep checkout
# You might see:
# 3d4e5f6 HEAD@{3}: checkout: moving from feature-awesome to main
# Find where you moved FROM feature-awesome
git checkout -b feature-awesome-recovered 3d4e5f6
Cherry-Picking: Surgical Commit Extraction
Cherry-picking lets you take specific commits from one branch and apply them to another. It’s like copy-pasting commits.
Basic cherry-pick:
# You're on main branch and want a specific commit from feature branch
git checkout main
# Find the commit you want
git log feature --oneline
# abc123 Add awesome feature
# def456 Fix typo
# ghi789 Update tests
# Cherry-pick the specific commit
git cherry-pick abc123
# The commit is now applied to main
Cherry-picking multiple commits:
# Pick a range of commits
git cherry-pick abc123..def456
# Pick specific commits (not a range)
git cherry-pick abc123 def456 ghi789
# Pick the last 3 commits from another branch
git cherry-pick feature~3..feature
Handling cherry-pick conflicts:
# Start cherry-pick
git cherry-pick abc123
# If there's a conflict
# Fix the conflicts in your editor
vim conflicted-file.txt
# Add the resolved files
git add conflicted-file.txt
# Continue the cherry-pick
git cherry-pick --continue
# Or abort if things go wrong
git cherry-pick --abort
Cherry-pick options:
# Cherry-pick but don't commit (stage changes only)
git cherry-pick -n abc123
# Cherry-pick and edit the commit message
git cherry-pick -e abc123
# Cherry-pick and add "cherry picked from" message
git cherry-pick -x abc123
# This adds a line like:
# (cherry picked from commit abc123...)
Advanced Reflog Techniques
Searching through reflog:
# Find all commits with specific message
git reflog --grep="feature"
# Show reflog for specific branch
git reflog show feature-branch
# Show reflog with dates
git reflog --date=relative
# Show reflog for all references
git reflog show --all
Time-based recovery:
# See where HEAD was yesterday
git show HEAD@{yesterday}
# See where HEAD was 2 hours ago
git show HEAD@{2.hours.ago}
# Reset to where you were this morning
git reset --hard HEAD@{10.hours.ago}
# See what main branch looked like last week
git show main@{1.week.ago}
Cleaning up after recovery:
# After recovering commits, clean up duplicate branches
git branch --merged | grep -v main | xargs git branch -d
# Garbage collect to clean up unreferenced objects (careful!)
git gc --prune=now
# See what would be cleaned up
git fsck --unreachable
Real-World Recovery Scenarios
Scenario 1: Lost work after force push
# Someone force-pushed to the remote
git pull
# Your local work seems gone!
# Find your work in reflog
git reflog
# Find your last commit before pull
# Create a branch from your work
git branch my-saved-work HEAD@{1}
# Now merge or rebase your work back
git rebase origin/main my-saved-work
Scenario 2: Recovering a specific file version
# You need a file from a deleted commit
git reflog
# Find the commit: abc123
# Get the file without checking out the commit
git show abc123:path/to/file.js > recovered-file.js
# Or restore it directly
git checkout abc123 -- path/to/file.js
Scenario 3: Undo last few operations
# You did several operations and want to undo them all
git reflog
# See your last "safe" point
# Create a backup of current state
git branch backup-current
# Reset to the safe point
git reset --hard HEAD@{10}
Best Practices and Safety Tips
1. Always create backup branches before dangerous operations:
# Before rebasing
git branch backup-before-rebase
# Before reset
git branch backup-before-reset
# Before merge
git branch backup-before-merge
2. Use git stash for temporary safety:
# Save current work before experimenting
git stash save "Before trying dangerous operation"
# Do your dangerous operation
git rebase -i HEAD~10
# If things go wrong, reset and restore stash
git reset --hard ORIG_HEAD
git stash pop
3. Configure reflog to keep entries longer:
# Keep reflog entries for 180 days
git config gc.reflogExpire 180.days
# Keep unreachable objects for 60 days
git config gc.reflogExpireUnreachable 60.days
4. Learn to read reflog patterns:
-
HEAD@{n}: The nth previous position of HEAD -
branch@{n}: The nth previous position of a specific branch -
@{-n}: The nth branch checked out before current -
@{upstream}: The upstream branch
Cherry-Pick vs Merge vs Rebase
When should you use cherry-pick instead of merge or rebase?
Use cherry-pick when:
- You need specific commits, not entire branches
- Backporting fixes to release branches
- Moving a commit to the correct branch
- Extracting commits from abandoned branches
Use merge when:
- Combining entire feature branches
- Preserving complete history
- Working with shared branches
Use rebase when:
- Cleaning up local history before pushing
- Updating feature branch with main
- Maintaining linear history
Troubleshooting Common Issues
“fatal: ambiguous argument ‘HEAD@{n}’”
# Escape the braces in some shells
git reset --hard 'HEAD@{1}'
# or
git reset --hard HEAD@\{1\}
“warning: reflog of ‘branch’ references pruned commits”
# The commits are still there, just unreachable
# Find them with
git fsck --unreachable | grep commit
# Recover specific unreachable commit
git show <unreachable-sha>
git branch recovered <unreachable-sha>
“error: could not apply abc123”
# Cherry-pick conflict
# See what's conflicting
git status
# See the differences
git diff
# Resolve and continue, or abort
git cherry-pick --abort
Conclusion
Git’s reflog is your safety net, and cherry-pick is your precision tool. Together, they make Git much less scary. Remember:
- Git rarely truly deletes anything immediately
- The reflog is your time machine - use it!
- Cherry-pick when you need surgical precision
- Always create backup branches before risky operations
- When in doubt, check the reflog
The next time you think you’ve lost work in Git, don’t panic. Take a breath, check the reflog, and remember that your commits are probably just a few commands away from recovery. Git has your back, you just need to know how to ask for help!
Practice these commands in a test repository until they become second nature. The confidence of knowing you can recover from almost any Git mistake is invaluable.
Until next time, may your commits be safe and your reflog always accessible!
-
Comments
Online: 0
Please sign in to be able to write comments.