prune Git Command Guide
The git prune command removes all unreachable objects from the object database. It identifies objects that are not reachable from any refs and permanently deletes them to reclaim storage space. This is typically run automatically by git gc.
git prune Syntax:
Section titled “git prune Syntax:”git prune [-n] [-v] [--progress] [--expire <time>] [--] [<head>...]Safety and Output Options:
Section titled “Safety and Output Options:”| Option | Description |
|---|---|
-n, --dry-run | Don’t remove anything, just report what would be removed |
-v, --verbose | Report all removed objects |
--progress | Show progress indicator |
Timing Options:
Section titled “Timing Options:”| Option | Description |
|---|---|
--expire <time> | Only expire loose objects older than |
Parameters:
Section titled “Parameters:”| Parameter | Description |
|---|---|
<head>... | Additional heads to consider reachable |
Understanding Object Reachability:
Section titled “Understanding Object Reachability:”Reachable vs Unreachable Objects:
Section titled “Reachable vs Unreachable Objects:”Reachable objects: Can be reached from refs (branches, tags, HEAD)├── Current commits on branches├── Objects referenced by current commits├── Objects in reflog (if --expire not used)└── Objects reachable from additional <head> parameters
Unreachable objects: Not reachable from any ref├── Old commits from rebased branches├── Objects from deleted branches/tags├── Dangling objects from interrupted operations└── Objects only in reflog (after expiration)Prune Process Flow:
Section titled “Prune Process Flow:”1. Identify: Find all refs (branches, tags, HEAD, reflog)2. Traverse: Walk object graph from all reachable refs3. Mark: Mark all reachable objects4. Sweep: Remove unmarked loose objects5. Clean: Remove unreachable entries from .git/shallowBasic Usage Examples:
Section titled “Basic Usage Examples:”Safe Pruning Operations:
Section titled “Safe Pruning Operations:”# Dry run to see what would be removedgit prune --dry-run
# Prune with verbose outputgit prune --verbose
# Prune with progress indicatorgit prune --progressTime-Based Pruning:
Section titled “Time-Based Pruning:”# Prune only objects older than 2 weeksgit prune --expire=2.weeks.ago
# Prune objects older than specific dategit prune --expire=2023-01-01
# Prune very old objects (conservative approach)git prune --expire=1.year.agoAdvanced Pruning:
Section titled “Advanced Pruning:”# Consider additional heads reachablegit prune HEAD refs/original/refs/heads/master
# Prune with custom expirationgit prune --expire=30.days.ago --verbose
# Safe pruning with backup verificationgit fsck --unreachable | grep commit > unreachable-before.txtgit prune --dry-rungit prune --verboseRepository Maintenance Scenarios:
Section titled “Repository Maintenance Scenarios:”Post-Rebase Cleanup:
Section titled “Post-Rebase Cleanup:”#!/bin/bash# Clean up after complex rebase operations
post_rebase_cleanup() { echo "Cleaning up after rebase..."
# Show unreachable objects before pruning echo "Unreachable objects before prune:" git fsck --unreachable | wc -l
# Prune unreachable objects git prune --verbose
# Clean up reflog entries git reflog expire --expire-unreachable=now --all
# Final verification echo "Unreachable objects after cleanup:" git fsck --unreachable | wc -l
echo "Post-rebase cleanup complete"}
post_rebase_cleanupRepository Size Optimization:
Section titled “Repository Size Optimization:”# Optimize repository size with careful pruningoptimize_repository_size() { echo "Optimizing repository size..."
# Analyze current size echo "Repository size before optimization:" du -sh .git/
# Count loose objects loose_count=$(find .git/objects -type f -name '[0-9a-f]*' | wc -l) echo "Loose objects: $loose_count"
# Safe pruning approach # First, expire old reflog entries git reflog expire --expire=3.months.ago --all
# Then prune with conservative expiration git prune --expire=2.months.ago --verbose
# Repack to consolidate git repack -a -d --depth=250 --window=250
# Final size check echo "Repository size after optimization:" du -sh .git/
loose_count_after=$(find .git/objects -type f -name '[0-9a-f]*' | wc -l) echo "Loose objects remaining: $loose_count_after"}
optimize_repository_sizeEmergency Repository Cleanup:
Section titled “Emergency Repository Cleanup:”# Emergency cleanup for bloated repositoriesemergency_cleanup() { echo "=== EMERGENCY REPOSITORY CLEANUP ===" echo "⚠ WARNING: This will permanently delete data ⚠"
# Create backup of current state backup_dir="repo-backup-$(date +%Y%m%d-%H%M%S)" mkdir -p "$backup_dir" cp -r .git "$backup_dir/"
echo "Backup created in: $backup_dir"
# Analyze current state echo "Current repository analysis:" git count-objects -v
# Aggressive but safe cleanup # 1. Clean reflog git reflog expire --expire=1.week.ago --all
# 2. Prune old objects git prune --expire=1.month.ago --verbose
# 3. Aggressive repack git repack -a -d -f
# 4. Final cleanup git gc --aggressive --prune=now
# Verify repository integrity if git fsck --full --strict; then echo "✓ Repository integrity verified" echo "Cleanup completed successfully"
# Remove backup after verification read -p "Remove backup directory $backup_dir? (y/N) " -n 1 -r if [[ $REPLY =~ ^[Yy]$ ]]; then rm -rf "$backup_dir" echo "Backup removed" fi else echo "✗ Repository corruption detected!" echo "Restore from backup: cp -r $backup_dir/.git .git" exit 1 fi}
# Use with extreme cautionemergency_cleanupConfiguration and Best Practices:
Section titled “Configuration and Best Practices:”Git Configuration for Pruning:
Section titled “Git Configuration for Pruning:”# Configure automatic pruning behaviorgit config gc.pruneExpire 2.weeks.ago # Default prune expirationgit config gc.reflogExpire 90.days # Reflog expirationgit config gc.reflogExpireUnreachable 30.days # Unreachable reflog expiration
# Configure maintenancegit config maintenance.gc.enabled truegit config maintenance.commit-graph.enabled truegit config maintenance.loose-objects.enabled trueSafe Pruning Practices:
Section titled “Safe Pruning Practices:”# Always run dry-run firstgit prune --dry-run --verbose
# Check what will be removedgit fsck --unreachable | head -20
# Verify repository health before pruninggit fsck --full --strict
# Backup important branches before aggressive pruninggit branch backup-$(date +%Y%m%d) # Create backup branch
# Use conservative expiration timesgit prune --expire=1.month.ago # Instead of --expire=nowMonitoring Prune Effectiveness:
Section titled “Monitoring Prune Effectiveness:”# Monitor repository object countsanalyze_object_counts() { echo "=== Repository Object Analysis ==="
# Count different object types echo "Object counts by type:" git cat-file --batch-check --batch-all-objects | \ cut -d' ' -f1 | sort | uniq -c | sort -nr
# Loose vs packed objects git count-objects -v
# Unreachable objects unreachable=$(git fsck --unreachable 2>/dev/null | wc -l) echo "Unreachable objects: $unreachable"
# Repository size echo "Repository size: $(du -sh .git/ | cut -f1)"}
analyze_object_countsIntegration with Git Workflows:
Section titled “Integration with Git Workflows:”Automated Maintenance Scripts:
Section titled “Automated Maintenance Scripts:”#!/bin/bash# Automated repository maintenance with safe pruning
automated_maintenance() { echo "Starting automated repository maintenance..."
# Pre-maintenance checks if ! git status --porcelain | grep -q .; then echo "✓ Working directory is clean" else echo "✗ Working directory has uncommitted changes" echo "Commit or stash changes before maintenance" exit 1 fi
# Create maintenance backup maintenance_backup="maintenance-backup-$(date +%Y%m%d-%H%M%S)" git branch "$maintenance_backup" echo "Maintenance backup created: $maintenance_backup"
# Safe maintenance steps echo "Step 1: Cleaning reflog..." git reflog expire --expire=30.days.ago --all
echo "Step 2: Pruning unreachable objects..." git prune --expire=2.weeks.ago --verbose
echo "Step 3: Repacking repository..." git repack -a -d --depth=250 --window=250
echo "Step 4: Updating auxiliary files..." git update-server-info
# Post-maintenance verification echo "Step 5: Verifying repository integrity..." if git fsck --connectivity-only --no-progress; then echo "✓ Repository integrity verified"
# Clean up maintenance backup git branch -D "$maintenance_backup" echo "Maintenance backup removed"
echo "✓ Automated maintenance completed successfully" else echo "✗ Repository integrity check failed!" echo "Maintenance backup preserved: $maintenance_backup" exit 1 fi}
automated_maintenanceCI/CD Pipeline Integration:
Section titled “CI/CD Pipeline Integration:”# Safe pruning in CI/CD pipelinesci_safe_prune() { echo "CI/CD safe pruning..."
# Only prune in clean CI environment if [ -n "$CI" ] && [ -z "$(git status --porcelain)" ]; then echo "✓ CI environment confirmed clean"
# Conservative pruning for CI git reflog expire --expire=1.day.ago --all git prune --expire=1.week.ago --quiet
# Update commit graph for performance git commit-graph write --reachable --changed-paths
echo "✓ CI pruning completed" else echo "Skipping pruning - not in clean CI environment" fi}
ci_safe_pruneRepository Migration Cleanup:
Section titled “Repository Migration Cleanup:”# Clean up after repository migrationpost_migration_cleanup() { local source_repo="$1"
echo "Post-migration cleanup for repository from $source_repo"
# Analyze what came from migration echo "Analyzing migrated objects..." git log --oneline --all | head -10
# Safe cleanup approach # 1. Preserve recent history git reflog expire --expire=1.year.ago --all
# 2. Prune old unreachable objects git prune --expire=6.months.ago --verbose
# 3. Optimize storage git gc --aggressive
# 4. Final verification git fsck --full --strict
echo "Post-migration cleanup complete"}
post_migration_cleanup "/path/to/source/repo"Troubleshooting Common Issues:
Section titled “Troubleshooting Common Issues:”Accidental Data Loss:
Section titled “Accidental Data Loss:”# If you accidentally pruned important datarecover_from_prune() { echo "Attempting to recover from accidental prune..."
# Check if reflog has the data git reflog | head -20
# Try to recover from reflog git checkout -b recovery HEAD@{1} # Or appropriate reflog entry
# If reflog doesn't help, check backups ls -la *.backup 2>/dev/null || echo "No local backups found"
# Last resort: contact colleagues for copies echo "Consider asking team members for repository copies"}
recover_from_pruneRepository Corruption After Prune:
Section titled “Repository Corruption After Prune:”# Diagnose and repair repository corruptionrepair_corrupted_repo() { echo "Diagnosing repository corruption..."
# Run detailed fsck git fsck --full --strict 2>&1 | tee fsck-report.txt
# Check for specific corruption types if grep -q "missing blob" fsck-report.txt; then echo "Missing blob objects detected" fi
if grep -q "dangling commit" fsck-report.txt; then echo "Dangling commits found - usually safe to ignore" fi
# Attempt repair echo "Attempting automatic repair..." if git fsck --full --strict --no-progress; then echo "✓ Repository appears healthy" else echo "✗ Repository corruption detected" echo "Consider restoring from backup" exit 1 fi}
repair_corrupted_repoPerformance Issues with Large Prunes:
Section titled “Performance Issues with Large Prunes:”# Handle large repository pruninglarge_repo_prune() { echo "Handling large repository prune..."
# Check system resources free -h df -h .
# Use incremental approach echo "Using incremental pruning approach..."
# Prune in smaller batches for age in 1.year 6.months 3.months 1.month; do echo "Pruning objects older than $age..." git prune --expire="$age".ago --quiet done
# Final aggressive cleanup git gc --aggressive --prune=2.weeks.ago
echo "Large repository pruning complete"}
large_repo_prunePermission and Access Issues:
Section titled “Permission and Access Issues:”# Handle permission issues during pruningfix_prune_permissions() { echo "Fixing prune permission issues..."
# Check permissions ls -la .git/objects/
# Fix ownership sudo chown -R $(whoami) .git/
# Fix permissions find .git -type d -exec chmod 755 {} \; find .git -type f -exec chmod 644 {} \;
# Retry prune git prune --dry-run
echo "Permission issues resolved"}
fix_prune_permissionsReal-World Usage Examples:
Section titled “Real-World Usage Examples:”Enterprise Repository Maintenance:
Section titled “Enterprise Repository Maintenance:”#!/bin/bash# Enterprise-scale repository maintenance
enterprise_repo_maintenance() { local repo_path="$1" local retention_days="${2:-90}"
cd "$repo_path"
echo "Enterprise repository maintenance for $(basename "$repo_path")"
# Pre-maintenance analysis echo "Pre-maintenance analysis:" git count-objects -v echo "Repository size: $(du -sh .git/ | cut -f1)"
# Create maintenance snapshot maintenance_tag="maintenance-$(date +%Y%m%d-%H%M%S)" git tag "$maintenance_tag" -m "Maintenance snapshot before cleanup"
# Safe maintenance procedure echo "Step 1: Reflog cleanup..." git reflog expire --expire="${retention_days} days ago" --all
echo "Step 2: Unreachable object pruning..." git prune --expire="${retention_days} days ago" --verbose
echo "Step 3: Repository repacking..." git repack -a -d --depth=250 --window=250
echo "Step 4: Auxiliary data update..." git update-server-info git commit-graph write --reachable
# Post-maintenance analysis echo "Post-maintenance analysis:" git count-objects -v echo "Repository size: $(du -sh .git/ | cut -f1)"
# Integrity verification if git fsck --connectivity-only --no-progress; then echo "✓ Repository integrity verified"
# Clean up maintenance tag after successful verification git tag -d "$maintenance_tag"
echo "✓ Enterprise maintenance completed successfully" else echo "✗ Repository integrity check failed!" echo "Maintenance tag preserved: $maintenance_tag" exit 1 fi}
enterprise_repo_maintenance "/repos/critical-project" 180Development Workflow Cleanup:
Section titled “Development Workflow Cleanup:”# Clean up development branches and unreachable objectsdev_workflow_cleanup() { echo "Development workflow cleanup..."
# Remove merged branches git branch --merged | grep -v "\*" | xargs -n 1 git branch -d 2>/dev/null || true
# Remove old remote branches git remote prune origin
# Clean up reflog git reflog expire --expire=30.days.ago --all
# Prune unreachable objects git prune --expire=2.weeks.ago --verbose
# Repack for efficiency git repack -a -d
echo "Development workflow cleanup complete"}
dev_workflow_cleanupDisaster Recovery Preparation:
Section titled “Disaster Recovery Preparation:”# Prepare repository for disaster recoverydisaster_recovery_prep() { echo "Preparing repository for disaster recovery..."
# Create comprehensive backup backup_file="disaster-recovery-$(date +%Y%m%d).bundle" git bundle create "$backup_file" --all
# Aggressive cleanup while preserving recoverability git reflog expire --expire=1.year.ago --all git prune --expire=6.months.ago --verbose
# Create recovery manifest cat > recovery-manifest.txt << EOFDisaster Recovery ManifestCreated: $(date)Backup file: $backup_fileRepository: $(pwd)Last commit: $(git rev-parse HEAD)Branches: $(git branch | wc -l)Tags: $(git tag | wc -l)Size after cleanup: $(du -sh .git/ | cut -f1)EOF
# Test recovery echo "Testing recovery from backup..." if git bundle verify "$backup_file" >/dev/null 2>&1; then echo "✓ Backup integrity verified" echo "Recovery preparation complete" else echo "✗ Backup verification failed!" exit 1 fi}
disaster_recovery_prepWhat’s the difference between git prune and git gc?
Section titled “What’s the difference between git prune and git gc?”git gc is a complete garbage collection that calls git prune plus other optimizations; git prune only removes unreachable loose objects. Use gc for comprehensive maintenance.
When should I run git prune manually?
Section titled “When should I run git prune manually?”Run manually when git gc —auto doesn’t trigger, or for specific cleanup needs. Most users should use git gc instead.
Can git prune delete reachable objects?
Section titled “Can git prune delete reachable objects?”No, git prune only removes objects unreachable from all refs. It uses git fsck —unreachable to identify safe deletions.
What’s the —expire option for?
Section titled “What’s the —expire option for?”Controls how old objects must be before pruning. Protects recently created unreachable objects (from interrupted operations).
How do I recover from accidental git prune?
Section titled “How do I recover from accidental git prune?”Check reflog for recoverable commits, restore from backups, or ask colleagues for repository copies. Prevention is better than recovery.
Can git prune work on bare repositories?
Section titled “Can git prune work on bare repositories?”Yes, operates on object database regardless of working directory. Essential for server-side repository maintenance.
What’s the impact of git prune on repository size?
Section titled “What’s the impact of git prune on repository size?”Removes loose unreachable objects, potentially significant space savings. Packed unreachable objects remain until repack -a -d.
How do I check what git prune will remove?
Section titled “How do I check what git prune will remove?”Use —dry-run —verbose to see exactly what objects would be removed without actually deleting them.
Can git prune cause repository corruption?
Section titled “Can git prune cause repository corruption?”No, when used correctly. It only removes objects verified as unreachable. Always run git fsck before and after.
What’s the relationship between prune and reflog?
Section titled “What’s the relationship between prune and reflog?”git prune considers reflog entries reachable by default. Use git reflog expire first to make reflog entries unreachable.
How do I handle git prune in automated scripts?
Section titled “How do I handle git prune in automated scripts?”Use —dry-run first, check exit codes, implement timeouts, and have recovery procedures. Log all operations.
Can git prune remove packed objects?
Section titled “Can git prune remove packed objects?”No, only removes loose unreachable objects. Use git repack -a -d to remove unreachable packed objects.
What’s the performance impact of git prune?
Section titled “What’s the performance impact of git prune?”Depends on repository size and loose object count. Can be slow on large repos with many loose objects.
How do I monitor git prune effectiveness?
Section titled “How do I monitor git prune effectiveness?”Compare git count-objects output before/after, check repository size changes, and monitor loose object counts.
Can git prune work with git worktrees?
Section titled “Can git prune work with git worktrees?”Yes, but operates on main repository object database. Worktree-specific objects are handled through the main repo.
What’s the safest way to run git prune?
Section titled “What’s the safest way to run git prune?”Use —dry-run —verbose first, ensure clean working directory, have backups, use conservative —expire times.
Applications of the git prune command
Section titled “Applications of the git prune command”- Repository Maintenance: Clean up unreachable objects to reclaim storage space and improve performance
- Post-Operation Cleanup: Remove objects left behind by rebases, branch deletions, and interrupted operations
- Storage Optimization: Reduce repository size by eliminating unnecessary loose objects
- Disaster Recovery: Prepare repositories for backup by removing expendable data
- Performance Tuning: Maintain optimal repository performance through regular cleanup
- Compliance Management: Support data retention policies by removing old unreachable objects