What's Actually Happening
Git reflog (reference log) records every change to HEAD - commits, resets, checkouts, merges, rebases. This creates a safety net: even if you delete commits or reset away work, reflog remembers where HEAD was. Entries expire after ~90 days, giving you time to recover lost work.
When You Need Reflog
- 1.Common scenarios:
- 2.Accidental reset -
git reset --hardremoved commits you wanted - 3.Bad rebase - Rebase went wrong and lost commits
- 4.Deleted branch - Branch with unpushed work was deleted
- 5.Amend overwritten -
git commit --amendreplaced a commit you needed - 6.Detached HEAD commits - Commits made in detached state and then abandoned
Step 1: View the Reflog
git reflogShows recent HEAD movements:
abc123d HEAD@{0}: reset: moving to HEAD~2
def4567 HEAD@{1}: commit: Important work I lost
ghi890j HEAD@{2}: commit: Previous commit
abc123d HEAD@{3}: checkout: moving from main to abc123dEach entry shows: - Commit hash where HEAD was - HEAD@{n} - index number for reference - Action that moved HEAD - Description of that action
Step 2: Find Your Lost Commit
Look through reflog for the commit you want:
```bash # Show more entries git reflog show HEAD -20
# Search for specific action git reflog show HEAD --grep="commit"
# Show timestamps git reflog show HEAD --date=iso ```
In our example, def4567 at HEAD@{1} is the lost commit.
Step 3: Recover the Commit
Create a branch pointing to the lost commit:
```bash # Recover using HEAD@{n} reference git branch recovered-work HEAD@{1}
# Or using commit hash directly git branch recovered-work def4567
# Switch to recovered branch git checkout recovered-work ```
Now verify your work is restored:
git log --oneline -3Shows recovered commits.
Step 4: Recover from Reset --hard
If you ran git reset --hard and lost work:
```bash # Example: you did this git reset --hard HEAD~3
# Check reflog git reflog # Output: # abc123d HEAD@{0}: reset: moving to HEAD~3 # old123 HEAD@{1}: commit: Third commit (lost) # old456 HEAD@{2}: commit: Second commit (lost) # old789 HEAD@{3}: commit: First commit (lost) # abc123d HEAD@{4}: checkout: moving to main
# Recover to state before reset git reset --hard HEAD@{1} # Or create branch git branch recovery HEAD@{1} ```
Step 5: Recover After Bad Rebase
If rebase went wrong:
```bash # You aborted rebase but commits missing git rebase --abort
# Check reflog git reflog # Look for "rebase: checkout" or "rebase finished"
# Find ORIG_HEAD (saved by rebase before starting) git show ORIG_HEAD
# Reset to pre-rebase state git reset --hard ORIG_HEAD ```
Step 6: Recover Deleted Branch
If you deleted a branch with unpushed commits:
```bash # Oops: git branch -D feature-branch
# Reflog still has entries git reflog # Find commits from deleted branch # Example: def4567 HEAD@{5}: checkout: moving from feature-branch to main
# Recreate branch at that commit git branch feature-branch-recovered def4567 ```
Step 7: Recover After Commit --amend
If amend overwrote a commit you needed:
```bash # Original commit was abc123d # You amended it to def4567
git reflog # Shows both: # def4567 HEAD@{0}: commit (amend): Amended version # abc123d HEAD@{1}: commit: Original commit
# Recover original git branch original-commit abc123d ```
Step 8: Cherry-Pick Specific Lost Commit
If you want to bring back just one commit:
```bash # Find commit hash from reflog git reflog | grep "some message"
# Cherry-pick it onto current branch git cherry-pick abc123d
# Or create branch from it git checkout -b recovered abc123d ```
Step 9: Check Reflog Expiry
Reflog entries expire after 90 days by default:
```bash # Check expiry settings git config --get gc.reflogExpire git config --get gc.reflogExpireUnreachable
# Set longer expiry git config --global gc.reflogExpire "180 days" ```
Verify the Fix
After recovery:
```bash # Check branch exists git branch -a
# Check commits are there git log --oneline recovered-work
# Verify file content git show recovered-work:path/to/file ```
Prevention Tips
Before risky operations, create backup:
```bash # Create backup branch before reset git branch backup-point
# Before risky rebase git branch pre-rebase-backup ```
If something goes wrong, you have the backup branch.