Skip to content

reflog Git Command Guide

The git reflog command manages the reflog (reference log) information that records when the tips of branches and other references were updated in the local repository. Reflogs are essential for recovery operations and provide a safety net for undoing destructive operations.

Terminal window
git reflog [show] [<log-options>] [<ref>]
git reflog list
git reflog exists <ref>
git reflog write <ref> <old-oid> <new-oid> <message>
git reflog delete [--rewrite] [--updateref]
[--dry-run | -n] [--verbose] <ref>@{<specifier>}...
git reflog drop [--all [--single-worktree] | <refs>...]
git reflog expire [--expire=<time>] [--expire-unreachable=<time>]
[--rewrite] [--updateref] [--stale-fix]
[--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]
CommandDescription
git reflog [show]Show reflog for HEAD (default)
git reflog <ref>Show reflog for specific reference
git reflog --allShow reflogs for all references
CommandDescription
git reflog listList all references with reflogs
git reflog exists <ref>Check if reflog exists for reference
git reflog write <ref> <old> <new> <msg>Write entry to reflog
CommandDescription
git reflog delete <entry>Delete specific reflog entry
git reflog drop <refs>Drop reflogs for references
git reflog expire <refs>Expire old reflog entries
OptionDescription
--dry-run, -nShow what would be done without doing it
--verboseShow detailed output
--allOperate on all reflogs
--single-worktreeOperate on single worktree only
--expire=<time>Set expiration time
--expire-unreachable=<time>Set unreachable expiration
ParameterDescription
<ref>Reference name (branch, HEAD, etc.)
<specifier>Reflog entry selector (HEAD@{1}, etc.)
<time>Time specification (90.days, 2.weeks, etc.)
Reflog (Reference Log):
├── Records all changes to reference tips
├── Local to each repository (not shared)
├── Safety net for recovery operations
├── Expires after configurable time (default 90 days)
├── Stored in .git/logs/refs/ directory
Reflog Entry Format:
abc123 HEAD@{0}: commit: Add new feature
def456 HEAD@{1}: merge develop: Merge branch 'develop'
ghi789 HEAD@{2}: reset: moving to HEAD~3
Comparison:
├── git log: Shows commit history (permanent)
├── git reflog: Shows reference changes (temporary)
├── git log: Shows what was committed
├── git reflog: Shows when refs were updated
├── git log: Same across repositories
├── git reflog: Unique to each repository
Specifier Examples:
├── HEAD@{0}: Current HEAD position
├── HEAD@{1}: Where HEAD was 1 change ago
├── master@{2}: Where master was 2 changes ago
├── HEAD@{yesterday}: HEAD position yesterday
├── HEAD@{2.days.ago}: HEAD position 2 days ago
├── HEAD@{one.week.ago}: HEAD position one week ago
Terminal window
# Show HEAD reflog (default)
git reflog
# Show specific branch reflog
git reflog show main
# Show all reflogs
git reflog --all
# Show reflog with dates
git reflog --date=relative
# Show reflog with full commit info
git reflog --pretty=fuller
Terminal window
# Checkout previous HEAD position
git checkout HEAD@{1}
# Show diff between current and previous
git diff HEAD@{0} HEAD@{1}
# Reset to previous position
git reset --hard HEAD@{2}
# Cherry-pick from reflog entry
git cherry-pick HEAD@{3}
# Create branch from reflog position
git checkout -b recovery-branch HEAD@{5}
Terminal window
# List all references with reflogs
git reflog list
# Check if reflog exists for reference
git reflog exists main
# Show reflog statistics
git reflog | wc -l # Count entries
Terminal window
# Write custom reflog entry
git reflog write HEAD abc123 def456 "Custom operation"
# Delete specific reflog entry
git reflog delete HEAD@{2}
# Delete with rewrite (update reference)
git reflog delete --rewrite HEAD@{bad-entry}
# Delete multiple entries
git reflog delete HEAD@{1} HEAD@{3} HEAD@{5}
Terminal window
# Expire old entries (dry run)
git reflog expire --dry-run --all
# Expire entries older than 30 days
git reflog expire --expire=30.days --all
# Expire unreachable entries
git reflog expire --expire-unreachable=7.days --all
# Clean up reflogs aggressively
git reflog expire --expire=now --all
Terminal window
# Drop reflogs for specific references
git reflog drop main develop
# Drop all reflogs
git reflog drop --all
# Drop reflogs for single worktree
git reflog drop --all --single-worktree
Terminal window
# Find when a commit was current HEAD
git reflog --grep="commit message"
# Show reflog for specific time period
git reflog --since="1 week ago"
# Count reflog entries by type
git reflog | awk '{print $3}' | sort | uniq -c
# Find reset operations
git reflog | grep "reset:"
Terminal window
# Configure reflog expiration
git config core.logAllRefUpdates true # Enable reflogs
git config gc.reflogExpire 90.days # Default expiration
git config gc.reflogExpireUnreachable 30.days # Unreachable expiration
# Configure reflog size limits
git config core.logAllRefUpdates always # Always log updates
git config gc.auto 256 # GC threshold
# Configure reflog display
git config log.date relative # Relative dates
git config log.decorate short # Decoration style
Terminal window
# Always check reflog before destructive operations
git reflog --oneline -10
# Create backup before complex operations
git branch backup-$(date +%Y%m%d-%H%M%S)
# Verify reflog integrity
git fsck --unreachable | grep reflog
# Monitor reflog size
du -sh .git/logs/
Terminal window
# Recovery workflow:
# 1. Check reflog for target position
git reflog show HEAD | head -20
# 2. Verify target commit
git show HEAD@{5}
# 3. Create recovery branch
git checkout -b recovery HEAD@{5}
# 4. Test recovery
git log --oneline -5
run-tests.sh
# 5. Apply recovery if successful
git checkout main
git reset --hard recovery
#!/bin/bash
# Emergency recovery using reflog
emergency_recovery() {
local target_ref="${1:-HEAD}"
local steps_back="${2:-5}"
echo "Emergency recovery for $target_ref"
# Show recent reflog entries
echo "Recent reflog entries:"
git reflog show "$target_ref" | head -10
# Create recovery options
for i in $(seq 0 "$steps_back"); do
commit=$(git rev-parse "$target_ref@{$i}" 2>/dev/null)
if [ $? -eq 0 ]; then
echo "$i: $(git log --oneline -1 "$commit")"
fi
done
# Prompt for recovery point
read -p "Enter recovery point number (or 'abort'): " choice
if [ "$choice" = "abort" ]; then
echo "Recovery aborted"
return 1
fi
# Perform recovery
if git checkout -b "recovery-$(date +%Y%m%d-%H%M%S)" "$target_ref@{$choice}"; then
echo "✓ Recovery branch created"
echo "Test the recovery branch before merging"
else
echo "✗ Recovery failed"
return 1
fi
}
emergency_recovery "HEAD" 10
Terminal window
# Audit repository changes using reflog
audit_changes() {
local since="${1:-1.week.ago}"
local author="${2:-}"
echo "Auditing changes since $since"
# Collect reflog data
git reflog --since="$since" --all |
while read -r line; do
# Parse reflog entry
ref=$(echo "$line" | awk '{print $1}')
action=$(echo "$line" | awk '{print $3}')
commit=$(echo "$line" | cut -d' ' -f2)
message=$(echo "$line" | cut -d' ' -f4-)
# Filter by author if specified
if [ -n "$author" ]; then
commit_author=$(git show --no-patch --format="%an" "$commit" 2>/dev/null)
[ "$commit_author" != "$author" ] && continue
fi
echo "$(date -d "$(echo "$line" | awk '{print $4" "$5}')") $ref $action $commit $message"
done | sort
}
audit_changes "2 days ago" "John Doe"
Terminal window
# Automated reflog cleanup and monitoring
reflog_maintenance() {
echo "Performing reflog maintenance..."
# Check reflog sizes
echo "Reflog sizes:"
find .git/logs -name "*" -type f -exec wc -l {} \; | sort -nr
# Expire old entries
git reflog expire --expire=90.days --expire-unreachable=30.days --all
# Compress repository
git gc --prune=now
# Report statistics
echo "Reflog statistics:"
git reflog | wc -l
du -sh .git/logs/
echo "Maintenance complete"
}
reflog_maintenance
Terminal window
# Recover missing reflog entries
recover_missing_reflog() {
echo "Attempting to recover missing reflog entries..."
# Check if reflogs are disabled
if [ "$(git config core.logAllRefUpdates)" = "false" ]; then
echo "Reflogs are disabled - enabling"
git config core.logAllRefUpdates true
fi
# Check reflog directory
ls -la .git/logs/refs/
# Try to reconstruct from other sources
git fsck --unreachable | grep commit
}
recover_missing_reflog
Terminal window
# Fix corrupted reflog files
fix_corrupted_reflog() {
local ref="$1"
echo "Fixing corrupted reflog for $ref..."
# Backup corrupted reflog
cp ".git/logs/refs/$ref" ".git/logs/refs/$ref.corrupted"
# Create new reflog entry
current_commit=$(git rev-parse "$ref")
git reflog write "$ref" "$current_commit" "$current_commit" "Recreated after corruption"
echo "Reflog recreated - original saved as .corrupted"
}
fix_corrupted_reflog "heads/main"
Terminal window
# Optimize reflog performance
optimize_reflog_performance() {
echo "Optimizing reflog performance..."
# Expire very old entries
git reflog expire --expire=1.year --all
# Run garbage collection
git gc --aggressive
# Reorganize reflog storage
git repack -a -d --depth=250 --window=250
echo "Reflog optimization complete"
}
optimize_reflog_performance
Terminal window
# Manage large reflog files
manage_large_reflog() {
echo "Managing large reflog files..."
# Find large reflog files
find .git/logs -type f -size +1M -exec ls -lh {} \;
# Archive old entries
for reflog in .git/logs/refs/*/*; do
if [ -f "$reflog" ] && [ $(wc -l < "$reflog") -gt 1000 ]; then
head -n 100 "$reflog" > "${reflog}.archive"
tail -n 100 "$reflog" > "${reflog}.tmp"
mv "${reflog}.tmp" "$reflog"
echo "Archived $reflog"
fi
done
echo "Reflog size management complete"
}
manage_large_reflog
Terminal window
# Query reflog by time periods
time_based_reflog() {
local time_spec="$1"
echo "Reflog entries for: $time_spec"
# Show entries from specific time
git reflog --since="$time_spec"
# Show entries until specific time
git reflog --until="$time_spec"
# Show entries between times
git reflog --since="1 week ago" --until="2 days ago"
}
time_based_reflog "yesterday"
Terminal window
# Recover accidentally deleted commits
recover_lost_commits() {
echo "Searching for lost commits..."
# Show recent reflog activity
git reflog --all --oneline | head -20
# Look for commits not in current branches
git fsck --unreachable | grep commit | cut -d' ' -f3 |
while read -r commit; do
if ! git branch --contains "$commit" >/dev/null 2>&1; then
echo "Potentially lost commit: $(git log --oneline -1 "$commit")"
fi
done
# Recover specific commit
read -p "Enter commit hash to recover: " lost_commit
git checkout -b recovered-commits "$lost_commit"
echo "Recovered commits available in branch: recovered-commits"
}
recover_lost_commits
Terminal window
# Recover from repository state corruption
repository_state_recovery() {
echo "Attempting repository state recovery..."
# Check current state
git status
# Find last known good state
git reflog --oneline | grep -E "(commit|merge|reset)" | head -10
# Attempt recovery to different points
for i in {1..5}; do
if git checkout -b "recovery-$i" "HEAD@{$i}" 2>/dev/null; then
echo "Created recovery branch: recovery-$i"
# Test if this state is good
if git status | grep -q "working tree clean"; then
echo "✓ Found good recovery state: recovery-$i"
break
fi
fi
done
echo "Recovery branches created - test each one"
}
repository_state_recovery
Terminal window
# Analyze development patterns using reflog
development_analysis() {
echo "Analyzing development patterns..."
# Most active branches
echo "Most active branches:"
git reflog --all | awk '{print $1}' | sort | uniq -c | sort -nr | head -5
# Reset frequency
echo "Reset operations:"
git reflog | grep "reset:" | wc -l
# Merge frequency
echo "Merge operations:"
git reflog | grep "merge" | wc -l
# Time-based activity
echo "Activity by hour:"
git reflog | awk '{print $4}' | cut -d: -f1 | sort | uniq -c | sort -nr
# Most common operations
echo "Common operations:"
git reflog | awk '{print $3}' | sort | uniq -c | sort -nr | head -10
}
development_analysis
Terminal window
# Recover from collaborative conflicts
collaborative_recovery() {
local branch="$1"
echo "Collaborative recovery for branch: $branch"
# Check branch reflog
git reflog show "$branch" | head -10
# Find last collaborative state
last_merge=$(git reflog show "$branch" | grep "merge" | head -1 | awk '{print $2}')
if [ -n "$last_merge" ]; then
echo "Last merge commit: $last_merge"
git checkout -b "recovery-from-merge" "$last_merge"
echo "Recovery branch created from last merge"
else
echo "No recent merges found"
fi
# Coordinate with team
echo "Coordinate with team before applying recovery"
}
collaborative_recovery "feature-team-project"
Terminal window
# Automated backup using reflog references
automated_backup() {
local backup_dir="${1:-/tmp/git-backups}"
local max_backups="${2:-10}"
echo "Creating automated backup..."
mkdir -p "$backup_dir"
# Create backup with reflog reference
backup_name="backup-$(date +%Y%m%d-%H%M%S)"
git bundle create "$backup_dir/$backup_name.bundle" HEAD@{0}
# Clean old backups
ls -t "$backup_dir"/*.bundle | tail -n +$((max_backups + 1)) | xargs rm -f
# Record backup in reflog
git reflog write HEAD "$(git rev-parse HEAD)" "$(git rev-parse HEAD)" "backup: $backup_name"
echo "Backup created: $backup_name"
echo "Location: $backup_dir/$backup_name.bundle"
}
automated_backup "/mnt/backups/git" 5
Terminal window
# Test repository states using reflog
reflog_testing() {
local test_command="$1"
echo "Testing repository states using reflog..."
# Test recent states
for i in {0..5}; do
if git checkout "HEAD@{$i}" 2>/dev/null; then
echo "Testing HEAD@{$i}: $(git log --oneline -1)"
if $test_command; then
echo "✓ Tests pass at HEAD@{$i}"
else
echo "✗ Tests fail at HEAD@{$i}"
fi
fi
done
# Return to original state
git checkout -
}
reflog_testing "npm test"

Reflog records all changes to branch tips and references. It’s crucial for recovery from mistakes like accidental resets, as it maintains a history of reference changes that git log doesn’t show.

Use git reflog to see HEAD reflog, or git reflog show for specific branches. Use git reflog —all to see all reflogs.

How do I recover from an accidental reset?

Section titled “How do I recover from an accidental reset?”

Check git reflog to find the commit before reset, then git reset —hard HEAD@{n} where n is the position before the reset.

By default, reflog entries are kept for 90 days for reachable commits and 30 days for unreachable ones. This is configurable.

Yes, but don’t: git config core.logAllRefUpdates false. Reflogs are essential for recovery and should only be disabled in bare repositories.

What’s the difference between HEAD@{1} and HEAD~1?

Section titled “What’s the difference between HEAD@{1} and HEAD~1?”

HEAD@{1} is the previous position of HEAD in reflog; HEAD~1 is the parent commit of current HEAD. They can be different after resets.

Use git reflog expire —expire=30.days —all to expire old entries, then git gc to clean up.

Yes, reflog files can become corrupted. If this happens, you can recreate them or recover from backups/other clones.

How do I find when a commit was current HEAD?

Section titled “How do I find when a commit was current HEAD?”

Use git reflog —grep="" or search through git reflog output for the commit hash.

No, reflogs are local to each repository clone. Each developer has their own reflog history.

If a branch was accidentally deleted, check git reflog —all for the last commit on that branch, then recreate: git checkout -b recovered-branch .

No, reflogs only track local references. Remote branches are tracked via remote-tracking branches, but their history isn’t reflogged locally.

Use du -sh .git/logs/ to check size, and git reflog | wc -l to count entries. Large reflogs may need cleanup.

What’s the impact of reflog on repository size?

Section titled “What’s the impact of reflog on repository size?”

Reflogs add minimal overhead but can grow large in active repositories. Regular git gc cleans up expired entries.

Reflogs are part of .git directory. Back up the entire .git folder to preserve reflogs, or use git bundle for portable backups.

Each entry shows: reference, old commit, new commit, timestamp, and operation description (commit, merge, reset, etc.).

  1. Emergency Recovery: Recover from accidental resets, rebases, or lost commits
  2. Repository State Analysis: Understand how repository state changed over time
  3. Development Auditing: Track development patterns and branch activities
  4. Branch Recovery: Restore accidentally deleted branches and commits
  5. History Investigation: Investigate when and how repository state changed
  6. Backup and Recovery: Create recovery points and backup strategies