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.
git reflog Syntax:
Section titled “git reflog Syntax:”git reflog [show] [<log-options>] [<ref>]git reflog listgit 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>...]Viewing Commands:
Section titled “Viewing Commands:”| Command | Description |
|---|---|
git reflog [show] | Show reflog for HEAD (default) |
git reflog <ref> | Show reflog for specific reference |
git reflog --all | Show reflogs for all references |
Management Commands:
Section titled “Management Commands:”| Command | Description |
|---|---|
git reflog list | List 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 |
Maintenance Commands:
Section titled “Maintenance Commands:”| Command | Description |
|---|---|
git reflog delete <entry> | Delete specific reflog entry |
git reflog drop <refs> | Drop reflogs for references |
git reflog expire <refs> | Expire old reflog entries |
Common Options:
Section titled “Common Options:”| Option | Description |
|---|---|
--dry-run, -n | Show what would be done without doing it |
--verbose | Show detailed output |
--all | Operate on all reflogs |
--single-worktree | Operate on single worktree only |
--expire=<time> | Set expiration time |
--expire-unreachable=<time> | Set unreachable expiration |
Parameters:
Section titled “Parameters:”| Parameter | Description |
|---|---|
<ref> | Reference name (branch, HEAD, etc.) |
<specifier> | Reflog entry selector (HEAD@{1}, etc.) |
<time> | Time specification (90.days, 2.weeks, etc.) |
Understanding Reflogs:
Section titled “Understanding Reflogs:”What is a Reflog?
Section titled “What is a Reflog?”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 featuredef456 HEAD@{1}: merge develop: Merge branch 'develop'ghi789 HEAD@{2}: reset: moving to HEAD~3Reflog vs Git Log:
Section titled “Reflog vs Git Log:”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 repositoryReflog Specifiers:
Section titled “Reflog Specifiers:”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 agoBasic Reflog Operations:
Section titled “Basic Reflog Operations:”Viewing Reflogs:
Section titled “Viewing Reflogs:”# Show HEAD reflog (default)git reflog
# Show specific branch refloggit reflog show main
# Show all reflogsgit reflog --all
# Show reflog with datesgit reflog --date=relative
# Show reflog with full commit infogit reflog --pretty=fullerUsing Reflog References:
Section titled “Using Reflog References:”# Checkout previous HEAD positiongit checkout HEAD@{1}
# Show diff between current and previousgit diff HEAD@{0} HEAD@{1}
# Reset to previous positiongit reset --hard HEAD@{2}
# Cherry-pick from reflog entrygit cherry-pick HEAD@{3}
# Create branch from reflog positiongit checkout -b recovery-branch HEAD@{5}Listing and Checking:
Section titled “Listing and Checking:”# List all references with reflogsgit reflog list
# Check if reflog exists for referencegit reflog exists main
# Show reflog statisticsgit reflog | wc -l # Count entriesAdvanced Reflog Management:
Section titled “Advanced Reflog Management:”Manual Reflog Entry Management:
Section titled “Manual Reflog Entry Management:”# Write custom reflog entrygit reflog write HEAD abc123 def456 "Custom operation"
# Delete specific reflog entrygit reflog delete HEAD@{2}
# Delete with rewrite (update reference)git reflog delete --rewrite HEAD@{bad-entry}
# Delete multiple entriesgit reflog delete HEAD@{1} HEAD@{3} HEAD@{5}Reflog Maintenance:
Section titled “Reflog Maintenance:”# Expire old entries (dry run)git reflog expire --dry-run --all
# Expire entries older than 30 daysgit reflog expire --expire=30.days --all
# Expire unreachable entriesgit reflog expire --expire-unreachable=7.days --all
# Clean up reflogs aggressivelygit reflog expire --expire=now --allBulk Reflog Operations:
Section titled “Bulk Reflog Operations:”# Drop reflogs for specific referencesgit reflog drop main develop
# Drop all reflogsgit reflog drop --all
# Drop reflogs for single worktreegit reflog drop --all --single-worktreeReflog Analysis:
Section titled “Reflog Analysis:”# Find when a commit was current HEADgit reflog --grep="commit message"
# Show reflog for specific time periodgit reflog --since="1 week ago"
# Count reflog entries by typegit reflog | awk '{print $3}' | sort | uniq -c
# Find reset operationsgit reflog | grep "reset:"Configuration and Best Practices:
Section titled “Configuration and Best Practices:”Git Configuration for Reflogs:
Section titled “Git Configuration for Reflogs:”# Configure reflog expirationgit config core.logAllRefUpdates true # Enable reflogsgit config gc.reflogExpire 90.days # Default expirationgit config gc.reflogExpireUnreachable 30.days # Unreachable expiration
# Configure reflog size limitsgit config core.logAllRefUpdates always # Always log updatesgit config gc.auto 256 # GC threshold
# Configure reflog displaygit config log.date relative # Relative datesgit config log.decorate short # Decoration styleSafe Reflog Practices:
Section titled “Safe Reflog Practices:”# Always check reflog before destructive operationsgit reflog --oneline -10
# Create backup before complex operationsgit branch backup-$(date +%Y%m%d-%H%M%S)
# Verify reflog integritygit fsck --unreachable | grep reflog
# Monitor reflog sizedu -sh .git/logs/Reflog Recovery Strategy:
Section titled “Reflog Recovery Strategy:”# Recovery workflow:# 1. Check reflog for target positiongit reflog show HEAD | head -20
# 2. Verify target commitgit show HEAD@{5}
# 3. Create recovery branchgit checkout -b recovery HEAD@{5}
# 4. Test recoverygit log --oneline -5run-tests.sh
# 5. Apply recovery if successfulgit checkout maingit reset --hard recoveryIntegration with Development Workflows:
Section titled “Integration with Development Workflows:”Emergency Recovery System:
Section titled “Emergency Recovery System:”#!/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" 10Reflog-Based Auditing:
Section titled “Reflog-Based Auditing:”# Audit repository changes using reflogaudit_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"Automated Reflog Maintenance:
Section titled “Automated Reflog Maintenance:”# Automated reflog cleanup and monitoringreflog_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_maintenanceTroubleshooting Common Issues:
Section titled “Troubleshooting Common Issues:”Missing Reflog Entries:
Section titled “Missing Reflog Entries:”# Recover missing reflog entriesrecover_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_reflogCorrupted Reflog Files:
Section titled “Corrupted Reflog Files:”# Fix corrupted reflog filesfix_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"Reflog Performance Issues:
Section titled “Reflog Performance Issues:”# Optimize reflog performanceoptimize_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_performanceReflog Size Management:
Section titled “Reflog Size Management:”# Manage large reflog filesmanage_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_reflogTime-Based Reflog Queries:
Section titled “Time-Based Reflog Queries:”# Query reflog by time periodstime_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"Real-World Usage Examples:
Section titled “Real-World Usage Examples:”Lost Commit Recovery:
Section titled “Lost Commit Recovery:”# Recover accidentally deleted commitsrecover_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_commitsRepository State Recovery:
Section titled “Repository State Recovery:”# Recover from repository state corruptionrepository_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_recoveryDevelopment History Analysis:
Section titled “Development History Analysis:”# Analyze development patterns using reflogdevelopment_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_analysisCollaborative Recovery:
Section titled “Collaborative Recovery:”# Recover from collaborative conflictscollaborative_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"Automated Backup with Reflog:
Section titled “Automated Backup with Reflog:”# Automated backup using reflog referencesautomated_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" 5Reflog-Based Testing:
Section titled “Reflog-Based Testing:”# Test repository states using reflogreflog_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"What is a reflog and why is it important?
Section titled “What is a reflog and why is it important?”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.
How do I view the reflog?
Section titled “How do I view the reflog?”Use git reflog to see HEAD reflog, or git reflog show
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.
How long are reflog entries kept?
Section titled “How long are reflog entries kept?”By default, reflog entries are kept for 90 days for reachable commits and 30 days for unreachable ones. This is configurable.
Can I disable reflogs?
Section titled “Can I disable reflogs?”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.
How do I clean up old reflog entries?
Section titled “How do I clean up old reflog entries?”Use git reflog expire —expire=30.days —all to expire old entries, then git gc to clean up.
Can reflogs be corrupted?
Section titled “Can reflogs be corrupted?”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="
Are reflogs shared between repositories?
Section titled “Are reflogs shared between repositories?”No, reflogs are local to each repository clone. Each developer has their own reflog history.
How do I use reflog for branch recovery?
Section titled “How do I use reflog for branch recovery?”If a branch was accidentally deleted, check git reflog —all for the last commit on that branch, then recreate: git checkout -b recovered-branch
Can I see reflog for remote branches?
Section titled “Can I see reflog for remote branches?”No, reflogs only track local references. Remote branches are tracked via remote-tracking branches, but their history isn’t reflogged locally.
How do I monitor reflog size?
Section titled “How do I monitor reflog size?”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.
Can I backup reflogs?
Section titled “Can I backup reflogs?”Reflogs are part of .git directory. Back up the entire .git folder to preserve reflogs, or use git bundle for portable backups.
How do I interpret reflog entries?
Section titled “How do I interpret reflog entries?”Each entry shows: reference, old commit, new commit, timestamp, and operation description (commit, merge, reset, etc.).
Applications of the git reflog command
Section titled “Applications of the git reflog command”- Emergency Recovery: Recover from accidental resets, rebases, or lost commits
- Repository State Analysis: Understand how repository state changed over time
- Development Auditing: Track development patterns and branch activities
- Branch Recovery: Restore accidentally deleted branches and commits
- History Investigation: Investigate when and how repository state changed
- Backup and Recovery: Create recovery points and backup strategies