Reflog - Your Safety Net

Architectural Foundation: Git’s Recovery Mechanism

The reference log (reflog) represents Git’s most critical safety mechanism—a time-ordered journal of every position HEAD and branch references have occupied. While Git’s content-addressable storage ensures data persistence, the reflog provides navigability through this data, enabling recovery of commits that appear “lost” after destructive operations.

Need to understand HEAD? Our Understanding HEAD guide explains what HEAD is, how it moves, and why the reflog tracks it.

Conceptual Model: The Reference Journal

Traditional version control systems lose data during operations like reset or branch deletion. Git’s reflog prevents this by maintaining a comprehensive audit trail.

Without Reflog (Theoretical Scenario):

Operation: git reset --hard HEAD~5
Result: Last 5 commits inaccessible (no references)
Recovery: Impossible (SHAs unknown)

With Reflog (Git’s Reality):

Operation: git reset --hard HEAD~5
Reflog: Records HEAD positions before and after
Recovery: git reflog → find SHA → git reset --hard <SHA>

Key Insight: Every Git operation that modifies references is logged, creating a recoverable trail even for “destructive” commands.


Technical Implementation: How Reflog Works

Storage Architecture

Reflog File Structure:

# Reflog stored per-reference
.git/logs/HEAD              # HEAD movements
.git/logs/refs/heads/main   # main branch movements
.git/logs/refs/heads/feature # feature branch movements

Reflog Entry Format:

<old-sha> <new-sha> <user> <timestamp> <tz> <action>

Example entry:
abc1234 def5678 John Developer <[email protected]> 1704067200 +0000	commit: Add feature

Entry Components:

  • old-sha: Previous commit reference pointed to
  • new-sha: New commit reference now points to
  • user: Developer who performed operation
  • timestamp: When operation occurred (Unix timestamp)
  • action: Description of operation

HEAD Reflog vs. Branch Reflogs

HEAD Reflog: Records all operations affecting HEAD position.

git reflog
# or
git reflog show HEAD

# Output:
abc1234 HEAD@{0}: commit: Add feature
def5678 HEAD@{1}: checkout: moving from feature to main
ghi9012 HEAD@{2}: commit: Fix bug
jkl3456 HEAD@{3}: rebase -i (finish): returning to refs/heads/feature

Branch Reflog: Records operations specific to a branch reference.

git reflog show main

# Output (only main-specific operations):
abc1234 main@{0}: merge feature: Fast-forward
def5678 main@{1}: commit: Update documentation
ghi9012 main@{2}: reset: moving to HEAD~1

Distinction: HEAD reflog shows your navigation; branch reflogs show branch history.


Reflog Reference Syntax

Temporal References

Absolute Position References:

HEAD@{0}    # Current HEAD position
HEAD@{1}    # Previous HEAD position
HEAD@{2}    # Two positions ago
HEAD@{n}    # N positions back

Time-Based References:

HEAD@{1.hour.ago}       # HEAD position 1 hour ago
HEAD@{yesterday}        # HEAD position yesterday
HEAD@{2.days.ago}       # HEAD position 2 days ago
HEAD@{1.week.ago}       # HEAD position 1 week ago
HEAD@{2024-01-15}       # HEAD position on specific date

Branch-Specific References:

main@{0}        # Current main tip
main@{1}        # Previous main tip
main@{3.days.ago}  # main position 3 days ago
feature@{yesterday}  # feature position yesterday

Reflog Query Operations

View Complete Reflog:

# Full reflog with details
git reflog show HEAD

# Compact format
git reflog

# With relative dates
git reflog --date=relative

# With ISO dates
git reflog --date=iso

Search Reflog:

# Find specific commit message
git reflog | grep "feature"

# Find operations on specific date
git reflog --since="2024-01-01" --until="2024-01-31"

# Find all rebase operations
git reflog | grep rebase

Inspect Specific Position:

# Show commit at reflog position
git show HEAD@{5}

# Show diff from that position
git diff HEAD@{5}

# Show log from that position
git log HEAD@{5}

Recovery Scenarios and Techniques

Scenario 1: Recovering from Accidental Hard Reset

Problem Context: Executed git reset --hard too aggressively, losing commits.

Example:

# Before reset
git log --oneline
abc1234 Recent work
def5678 Important feature
ghi9012 Critical fix
jkl3456 Base commit

# Accidental reset
git reset --hard HEAD~3

# After reset (lost commits)
git log --oneline
jkl3456 Base commit
# abc1234, def5678, ghi9012 gone!

Recovery Process:

Step 1: Examine Reflog

git reflog

# Output shows reset operation:
jkl3456 HEAD@{0}: reset: moving to HEAD~3
abc1234 HEAD@{1}: commit: Recent work
def5678 HEAD@{2}: commit: Important feature
ghi9012 HEAD@{3}: commit: Critical fix

Step 2: Identify Target Commit

# HEAD@{1} contains the lost "Recent work"
git show HEAD@{1}

# Verify this is correct commit
git log --oneline HEAD@{1}

Step 3: Restore to Previous State

# Reset to before destructive operation
git reset --hard HEAD@{1}

# Verify recovery
git log --oneline
abc1234 Recent work    # ✅ Recovered
def5678 Important feature
ghi9012 Critical fix
jkl3456 Base commit

Scenario 2: Recovering Deleted Branch

Problem Context: Accidentally deleted branch with unmerged work.

Example:

# Feature branch with commits
git checkout feature-important
git log --oneline
abc1234 Feature work 3
def5678 Feature work 2
ghi9012 Feature work 1

# Switch to main
git checkout main

# Accidentally delete feature branch
git branch -D feature-important
# Deleted branch feature-important (was abc1234).

# Realize mistake: feature-important had unmerged work!

Recovery Process:

Step 1: Find Branch in Reflog

# Search for branch in reflog
git reflog | grep "feature-important"

# Output:
ghi9012 HEAD@{3}: checkout: moving from main to feature-important
abc1234 HEAD@{1}: commit: Feature work 3

Step 2: Identify Branch Tip

# abc1234 was the last commit on branch
git show abc1234

Step 3: Recreate Branch

# Create new branch at that commit
git branch feature-important abc1234

# Or using reflog reference
git branch feature-important HEAD@{1}

# Verify recovery
git checkout feature-important
git log --oneline
abc1234 Feature work 3    # ✅ Recovered
def5678 Feature work 2
ghi9012 Feature work 1

Scenario 3: Recovering from Failed Rebase

Problem Context: Interactive rebase went wrong; want to return to pre-rebase state.

Example:

# Before rebase
git log --oneline
abc1234 Commit 5
def5678 Commit 4
ghi9012 Commit 3
jkl3456 Commit 2
mno7890 Commit 1

# Start interactive rebase
git rebase -i HEAD~5
# Make mistakes during rebase
# Result: Mangled commit history

Recovery Process:

Step 1: Check Reflog for Rebase Start

git reflog

# Output shows rebase operations:
pqr1111 HEAD@{0}: rebase -i (finish): returning to refs/heads/feature
stu2222 HEAD@{1}: rebase -i (squash): Combined commits
abc1234 HEAD@{5}: rebase -i (start): checkout HEAD~5

Step 2: Reset to Pre-Rebase State

# Find position before rebase started
# Look for "rebase -i (start)"
git reset --hard HEAD@{5}

# Or use ORIG_HEAD (Git's automatic bookmark)
git reset --hard ORIG_HEAD

ORIG_HEAD Shortcut: Git automatically sets ORIG_HEAD before dangerous operations.

# After rebase, immediately undo with:
git reset --hard ORIG_HEAD

Limitation: ORIG_HEAD only preserved until next operation that sets it (merge, reset, rebase).


Scenario 4: Recovering Lost Commits After Merge

Problem Context: Merge didn’t go as expected; want to undo merge and restore original state.

Example:

# Merge feature into main
git checkout main
git merge feature

# Result unsatisfactory, want to undo

Recovery Process:

Step 1: Find Pre-Merge State

git reflog

# Output:
abc1234 HEAD@{0}: merge feature: Merge made by the 'ort' strategy.
def5678 HEAD@{1}: checkout: moving from feature to main

Step 2: Reset to Before Merge

git reset --hard HEAD@{1}

# Or:
git reset --hard ORIG_HEAD

Scenario 5: Finding Specific Lost Commit

Problem Context: Know commit existed recently but can’t find reference to it.

Search Strategy:

By Commit Message:

git reflog | grep "authentication"

# Output:
abc1234 HEAD@{15}: commit: Add authentication

By Date Range:

git reflog --since="2.days.ago" --until="1.day.ago"

By Operation Type:

# Find all commits (not checkouts or merges)
git reflog | grep "commit:"

# Find all rebases
git reflog | grep "rebase"

# Find all merges
git reflog | grep "merge"

Once Found:

# Create branch at that commit
git branch recovered-work abc1234

# Or cherry-pick it
git cherry-pick abc1234

# Or view it
git show abc1234

Advanced Reflog Techniques

Technique 1: Branch-Specific Recovery

Purpose: Recover specific branch history even when multiple branches are involved.

# Feature branch deleted, but want its history
git reflog show feature-branch

# Output shows feature branch movements:
abc1234 feature-branch@{0}: commit: Last feature work
def5678 feature-branch@{1}: commit: Feature progress
ghi9012 feature-branch@{2}: branch: Created from main

# Recreate branch at last position
git branch feature-branch abc1234

Technique 2: Reflog Pruning and Expiration

Default Expiration Settings:

# View current settings
git config --get gc.reflogExpire          # Default: 90 days
git config --get gc.reflogExpireUnreachable  # Default: 30 days

Expiration Rules:

  • Reachable entries: Expire after 90 days (commits still referenced)
  • Unreachable entries: Expire after 30 days (commits no longer referenced)

Custom Expiration Configuration:

# Extend reflog retention for critical repositories
git config gc.reflogExpire "365 days"
git config gc.reflogExpireUnreachable "180 days"

# Never expire (use cautiously - increases repository size)
git config gc.reflogExpire "never"

# Per-branch custom expiration
git config gc.refs/heads/main.reflogExpire "1 year"

Manual Reflog Cleanup:

# Trigger garbage collection (respects expiration settings)
git gc

# Force garbage collection with aggressive pruning
git gc --prune=now --aggressive

# Preview what would be pruned
git reflog expire --dry-run --all

Technique 3: Reflog Across Clones

Important Limitation: Reflog is local only—not shared between clones.

Scenario:

# Original repository
cd original-repo
git reflog  # Shows full history

# Clone repository
git clone original-repo cloned-repo
cd cloned-repo
git reflog  # Shows only operations since clone

Implication: Cannot recover operations from another developer’s clone via reflog.

Workaround for Team Recovery:

  • Request original developer’s reflog output
  • Identify commit SHA
  • Fetch that commit if it still exists in remote

Technique 4: Reflog in Detached HEAD State

Detached HEAD Commits: Often considered “lost” but recorded in reflog.

Example:

# Enter detached HEAD state
git checkout abc1234

# Make commits
vim file.py
git commit -am "Experimental change 1"
git commit -am "Experimental change 2"

# Return to branch (commits appear lost)
git checkout main

# Recover via reflog
git reflog

# Output shows detached HEAD commits:
def5678 HEAD@{2}: commit: Experimental change 2
ghi9012 HEAD@{3}: commit: Experimental change 1
abc1234 HEAD@{4}: checkout: moving from main to abc1234

# Create branch for experimental work
git branch experiment-work def5678

Reflog Inspection and Analysis

Detailed Reflog Examination

Verbose Reflog Output:

# Show reflog with full commit messages
git reflog show -3 --date=iso

# Output:
abc1234 (HEAD -> main) HEAD@{2024-01-15 10:30:00 +0000}: commit: Add user authentication
def5678 HEAD@{2024-01-15 09:15:00 +0000}: reset: moving to HEAD~1
ghi9012 HEAD@{2024-01-15 08:45:00 +0000}: commit: Fix validation bug

Statistical Analysis:

# Count reflog entries
git reflog | wc -l

# Find most recent operations
git reflog -10

# Find operations by specific user (in multi-user environments)
git reflog | grep "[email protected]"

Reflog Diff Analysis

Compare Current State with Reflog Position:

# See what changed since reflog position
git diff HEAD@{5}

# See what changed between two reflog positions
git diff HEAD@{5}..HEAD@{2}

# Statistical diff
git diff --stat HEAD@{10}

Log Analysis from Reflog Position:

# Show commits since reflog position
git log HEAD@{5}..HEAD

# Compact format
git log --oneline HEAD@{10}..HEAD

Integration with Recovery Workflows

Complete Recovery Protocol

Systematic Recovery Steps:

  1. Assess Situation
# What's the current state?
git status
git log --oneline -5

# What was lost?
# (Commits, branches, stashed work)
  1. Examine Reflog
# Review recent operations
git reflog -20

# Search for specific operation
git reflog | grep "branch-name"
git reflog | grep "commit-message-fragment"
  1. Identify Target Commit
# Show commit details
git show HEAD@{n}

# Verify this is correct commit
git log --oneline HEAD@{n}
  1. Perform Recovery
# Option A: Reset to position
git reset --hard HEAD@{n}

# Option B: Create branch at position
git branch recovered-work HEAD@{n}

# Option C: Cherry-pick specific commits
git cherry-pick HEAD@{n}
  1. Verify Recovery
# Check repository state
git status
git log --oneline

# Run tests
npm test

# Verify file contents
git diff HEAD@{n}  # Should show minimal differences

Recovery Decision Tree

Lost Work?
  ├─ Accidental Reset? → git reflog → git reset --hard HEAD@{n}
  ├─ Deleted Branch? → git reflog | grep branch → git branch name SHA
  ├─ Failed Rebase? → git reset --hard ORIG_HEAD or HEAD@{before-rebase}
  ├─ Bad Merge? → git reset --hard ORIG_HEAD
  ├─ Lost Commit? → git reflog | grep message → git cherry-pick SHA
  └─ Detached HEAD Commits? → git reflog → git branch name HEAD@{n}

Reflog Limitations and Caveats

Limitation 1: Expiration

Default Behavior: Reflog entries expire after 90 days (reachable) or 30 days (unreachable).

Implication: Cannot recover very old operations.

Mitigation:

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

Limitation 2: Local Only

Problem: Reflog doesn’t synchronize across clones or remotes.

Scenario: Teammate’s repository has lost commits; your reflog doesn’t help.

Solution: Focus on recovering from their local reflog or use git fsck for unreferenced commits.


Limitation 3: Garbage Collection

Problem: Unreferenced commits eventually garbage collected even if in reflog.

Timeline:

  1. Commit becomes unreferenced
  2. Remains in reflog for 30 days (default)
  3. After 30 days, eligible for garbage collection
  4. git gc runs and removes unreferenced objects

Prevention:

# Disable aggressive garbage collection
git config gc.autopacklimit 0
git config gc.auto 0

# Or extend unreachable expiration
git config gc.reflogExpireUnreachable "365 days"

Limitation 4: Reflog Can’t Recover Everything

What Reflog CAN’T Recover:

  • ❌ Uncommitted changes discarded by git reset --hard
  • ❌ Untracked files deleted with git clean -f
  • ❌ Stashes dropped with git stash drop
  • ❌ Changes in working tree never staged

What Reflog CAN Recover:

  • ✅ Committed work
  • ✅ Commits “lost” after reset
  • ✅ Deleted branches
  • ✅ Failed rebases or merges
  • ✅ Detached HEAD commits

Advanced Recovery: When Reflog Isn’t Enough

Using git fsck for Deep Recovery

Purpose: Find objects not referenced by any branch or reflog.

# Find dangling commits
git fsck --lost-found

# Output:
dangling commit abc1234567890
dangling commit def9876543210

# Examine dangling commits
git show abc1234567890

# Recover useful commit
git branch recovered-work abc1234567890

Use Case: Commit older than reflog expiration or reflog corrupted.


Combining Reflog with git log --all

Purpose: Search all reachable commits, not just current branch.

# Search all commits in repository
git log --all --grep="authentication"

# Find by author
git log --all --author="[email protected]"

# Find by date
git log --all --since="2.weeks.ago"

Best Practices and Guidelines

Practice 1: Regular Reflog Review

Periodic Audit:

# Weekly review of significant operations
git reflog -50

# Identify risky operations
git reflog | grep -E "reset|rebase|merge"

Benefits:

  • Awareness of repository state changes
  • Early detection of mistakes
  • Familiarity with recovery process

Practice 2: Document Important Operations

Commit Message References:

# Include reflog position in recovery commits
git commit -m "Recover work from HEAD@{15} after accidental reset"

Operation Logging:

# Keep notes of complex operations
echo "$(date): Rebased feature branch, original at $(git rev-parse HEAD)" >> .git/operation-log

Practice 3: Extended Retention for Critical Repositories

Configuration for Important Projects:

# Production repositories
git config gc.reflogExpire "1 year"
git config gc.reflogExpireUnreachable "6 months"

# Personal projects (default is fine)
git config gc.reflogExpire "90 days"

Practice 4: Backup Before Dangerous Operations

Pre-Operation Protection:

# Before complex rebase
git branch backup-before-rebase

# Perform rebase
git rebase -i HEAD~10

# If successful, delete backup
git branch -D backup-before-rebase

# If failed, restore from backup instead of relying solely on reflog
git reset --hard backup-before-rebase

Summary: Reflog as Recovery Foundation

Core Capabilities:

  1. Operation Journaling: Records every HEAD and reference movement
  2. Temporal Navigation: Access repository state at any reflog position
  3. Lost Commit Recovery: Find and restore “deleted” commits
  4. Branch Reconstruction: Recreate deleted branches
  5. Operation Auditing: Review history of repository modifications

Strategic Value:

  • Safety Net: Enables undo for “destructive” Git operations
  • Confidence: Reduces fear of experimenting with advanced Git features
  • Debugging: Traces operation sequences leading to problems
  • Recovery: Restores lost work that would be unrecoverable in other VCS

Limitations to Remember:

  • Local only (not synchronized across clones)
  • Time-limited (default 90 days for reachable, 30 for unreachable)
  • Cannot recover uncommitted changes
  • Subject to garbage collection

Practical Application:

  • Review reflog after mistakes: git reflog
  • Recovery pattern: identify → verify → restore
  • Use ORIG_HEAD for immediate undo of rebase/merge/reset
  • Combine with git fsck for deep recovery
  • Configure extended retention for critical repositories

Technical Excellence: The reflog transforms Git from a tool with “dangerous” commands into a system with comprehensive recovery capabilities. Understanding reflog mechanics enables confident use of advanced Git features, knowing that mistakes are recoverable within the reflog retention window.


Master Git’s recovery mechanisms Explore Advanced Techniques