Git Reflog: Your Safety Net for Lost Commits

David Childs

Git reflog is your time machine and safety net rolled into one. When you think you've lost commits, accidentally deleted branches, or made a terrible mistake, reflog is there to save the day. It records every change to your repository's HEAD, creating a complete history of where you've been.

Understanding Git Reflog

Reflog (reference log) tracks when the tips of branches and other references were updated in your local repository. Unlike the commit history, reflog includes:

  • Commits that were abandoned
  • Branches that were deleted
  • Commits lost during rebases
  • Any HEAD movement in your repository

Think of it as Git's "undo" history—a record of everything you've done, even things not in your commit graph anymore.

Basic Reflog Commands

Viewing the Reflog

# Show reflog for HEAD
git reflog
# or
git reflog show

# Sample output
abc1234 HEAD@{0}: commit: Fix payment bug
def5678 HEAD@{1}: checkout: moving from feature to main
ghi9012 HEAD@{2}: commit: Add payment feature
jkl3456 HEAD@{3}: checkout: moving from main to feature

Reflog for Specific References

# Reflog for specific branch
git reflog show main
git reflog show feature-branch

# Reflog for stash
git reflog show stash

# Detailed reflog with dates
git reflog --date=relative
git reflog --date=iso

Common Recovery Scenarios

1. Recovering Lost Commits

You accidentally reset your branch and lost commits:

# Oops! Lost your last 3 commits
git reset --hard HEAD~3

# Don't panic! Check reflog
git reflog
# abc1234 HEAD@{0}: reset: moving to HEAD~3
# def5678 HEAD@{1}: commit: Important feature  <-- Want this back!

# Recover the lost commit
git reset --hard HEAD@{1}
# or
git reset --hard def5678

2. Recovering Deleted Branches

Accidentally deleted a branch with important work:

# Deleted a branch
git branch -D feature-important

# Find the branch's last commit
git reflog | grep feature-important
# ghi9012 HEAD@{5}: checkout: moving from feature-important to main

# Recreate the branch
git branch feature-important ghi9012

# Or checkout directly
git checkout -b feature-important ghi9012

3. Undoing a Bad Merge

Merged the wrong branch and want to undo:

# Bad merge happened
git merge feature-experimental
# Conflicts, problems, chaos!

# Check reflog to find state before merge
git reflog
# abc1234 HEAD@{0}: merge feature-experimental: Merge made
# def5678 HEAD@{1}: commit: Last good commit

# Reset to before the merge
git reset --hard HEAD@{1}

4. Recovering from Failed Rebase

Rebase went wrong and you want to abort:

# Rebase gone wrong
git rebase main
# Conflicts everywhere!

# If still in rebase
git rebase --abort

# If rebase completed but went badly
git reflog
# Find commit before rebase started
git reset --hard HEAD@{5}  # Or appropriate reflog entry

Advanced Reflog Techniques

Time-Based Recovery

# Find HEAD position at specific time
git reflog --date=iso
git reflog --since="2 hours ago"
git reflog --until="yesterday"

# Recover to specific time
git reset --hard HEAD@{2.hours.ago}
git reset --hard HEAD@{yesterday}
git reset --hard HEAD@{2024-01-15.14:30:00}

Searching Reflog

# Search reflog messages
git reflog | grep "payment"

# Search with context
git reflog --grep="feature" --walk-reflogs

# Find specific operations
git reflog | grep -E "merge|rebase|reset"

Reflog Expiration

# Check reflog expiration settings
git config gc.reflogExpire
git config gc.reflogExpireUnreachable

# Manually expire old reflog entries
git reflog expire --expire=30.days --all

# Keep reflog forever (not recommended for large repos)
git config gc.reflogExpire never

Practical Recovery Workflows

The "Oh No!" Recovery Process

#!/bin/bash
# recovery-helper.sh

echo "Git Recovery Helper"
echo "==================="
echo ""
echo "Recent reflog entries:"
git reflog -10 --date=relative

echo ""
echo "What did you lose?"
echo "1) Commits after reset"
echo "2) Deleted branch"
echo "3) Bad merge"
echo "4) Failed rebase"
echo "5) Stashed changes"

read -p "Select option (1-5): " option

case $option in
    1)
        echo "Last 5 resets:"
        git reflog | grep -E "reset:" | head -5
        read -p "Enter SHA or HEAD@{n} to recover to: " target
        git reset --hard $target
        ;;
    2)
        read -p "Enter branch name: " branch
        sha=$(git reflog | grep "checkout: moving from $branch" | head -1 | awk '{print $1}')
        git checkout -b $branch $sha
        ;;
    3)
        before_merge=$(git reflog | grep -B1 "merge" | head -1 | awk '{print $1}')
        git reset --hard $before_merge
        ;;
    4)
        before_rebase=$(git reflog | grep -B1 "rebase" | head -1 | awk '{print $1}')
        git reset --hard $before_rebase
        ;;
    5)
        git stash list
        git reflog show stash
        ;;
esac

Creating Safety Checkpoints

# Before risky operation
git branch backup-before-rebase

# Or tag it
git tag backup-$(date +%Y%m%d-%H%M%S)

# After operation, if successful
git branch -D backup-before-rebase

# If failed, recover
git reset --hard backup-before-rebase

Reflog and Remote Repositories

Important: Reflog is Local Only

# Reflog doesn't sync with remote
git push  # Reflog stays local

# Each clone has its own reflog
git clone repo new-clone
cd new-clone
git reflog  # Empty except for clone operation

Recovering Pushed Then Lost Commits

# If you pushed before losing
git fetch origin

# Find in remote tracking branches
git log origin/main

# Cherry-pick or merge lost commits
git cherry-pick origin/main~2..origin/main

Reflog for Different Operations

Stash Reflog

# View stash reflog
git reflog show stash

# Recover dropped stash
git reflog show stash | grep "WIP on"
# stash@{2}: WIP on main: abc1234 Important work

# Apply old stash entry
git stash apply stash@{2}

Branch Reflog

# See specific branch history
git reflog show feature-branch

# Recover branch to previous state
git checkout feature-branch
git reset --hard feature-branch@{2}

Tag Recovery

# Accidentally deleted tag
git tag -d v1.0.0

# Find in reflog
git reflog | grep "tag: v1.0.0"
# abc1234 HEAD@{10}: commit: Release v1.0.0

# Recreate tag
git tag v1.0.0 abc1234

Combining Reflog with Other Commands

Reflog + Bisect

# Find when bug was introduced
git bisect start
git bisect bad HEAD
git bisect good HEAD@{30}  # Known good from reflog

Reflog + Cherry-pick

# Cherry-pick lost commits
git reflog | grep "feature work"
git cherry-pick HEAD@{5}
git cherry-pick HEAD@{7}..HEAD@{10}

Reflog + Diff

# See what changed between reflog entries
git diff HEAD@{5} HEAD@{0}

# See files changed
git diff --name-only HEAD@{10} HEAD

Best Practices

1. Regular Reflog Maintenance

# Check reflog size
du -sh .git/logs

# Clean old entries (default 90 days unreachable, 30 days reachable)
git reflog expire --expire=now --all
git gc --prune=now

2. Descriptive Commit Messages

# Good messages make reflog more useful
git commit -m "feat: Add payment processing with Stripe"
# Better than
git commit -m "stuff"

# Reflog becomes self-documenting

3. Create Recovery Aliases

# Useful reflog aliases
git config --global alias.undo "reset --hard HEAD@{1}"
git config --global alias.find "!git reflog | grep"
git config --global alias.recovery-point "!git branch recovery-$(date +%s)"

Troubleshooting with Reflog

Finding When File Was Deleted

# When was file.txt deleted?
git reflog --all -- file.txt

# Or search through history
for ref in $(git reflog --format="%h"); do
    git ls-tree -r $ref --name-only | grep -q "file.txt" && echo "$ref has file.txt"
done

Debugging Mysterious Changes

# When did this line appear?
git reflog | while read sha rest; do
    git show $sha:file.txt 2>/dev/null | grep -q "mysterious line" && echo "$sha: $rest"
done

Recovery Verification

# Verify recovery was successful
before_recovery=$(git rev-parse HEAD)
git reset --hard HEAD@{5}
after_recovery=$(git rev-parse HEAD)

if [ "$before_recovery" != "$after_recovery" ]; then
    echo "Recovery successful"
    git log --oneline -5
else
    echo "No changes made"
fi

Common Pitfalls

1. Reflog Expires

# Default expiration
# - 90 days for unreachable commits
# - 30 days for reachable commits

# Extend expiration for important repos
git config gc.reflogExpire "365 days"
git config gc.reflogExpireUnreachable "365 days"

2. Forced Garbage Collection

# This removes reflog entries!
git gc --prune=now --aggressive

# Safer approach
git gc --auto

3. Shallow Clones

# Shallow clones have limited reflog
git clone --depth=1 repo

# Convert to full clone for complete reflog
git fetch --unshallow

Real-World Recovery Examples

Example 1: Production Hotfix Gone Wrong

# Made changes directly on production branch
git checkout production
# ... made changes ...
git reset --hard origin/production  # Lost local changes!

# Recovery
git reflog
# Find your commits
git cherry-pick HEAD@{2}..HEAD@{5}

Example 2: Interactive Rebase Disaster

# Messed up during interactive rebase
git rebase -i HEAD~10
# Accidentally deleted important commits

# Find pre-rebase state
git reflog | grep "rebase -i (start)"
# Reset to before rebase
git reset --hard HEAD@{15}

Example 3: Wrong Branch Merge

# Merged experimental branch to main instead of develop
git checkout main
git merge experimental-feature  # Wrong!

# Quick recovery
git reflog
git reset --hard HEAD@{1}  # Before merge
git checkout develop
git merge experimental-feature  # Correct branch

Conclusion

Git reflog is your insurance policy against Git mishaps. It's the safety net that lets you experiment fearlessly, knowing you can always go back. While it shouldn't replace good Git practices, understanding reflog transforms "oh no!" moments into "no problem!" solutions.

Remember: in Git, very little is truly lost. Between reflog, the object database, and Git's robust architecture, your code is safer than you might think. Master reflog, and you'll never fear Git commands again.

The key is acting quickly—reflog entries do expire. When disaster strikes, don't panic. Check the reflog, find your lost work, and recover with confidence.

Share this article

DC

David Childs

Consulting Systems Engineer with over 10 years of experience building scalable infrastructure and helping organizations optimize their technology stack.

Related Articles