How to prune remote branches in Git
Remote branch pruning removes stale references to deleted remote branches, keeping local repository clean and preventing confusion from outdated branch listings. As the creator of CoreUI, a widely used open-source UI library, I’ve maintained clean Git repositories across distributed teams throughout my 25 years of development experience. The most effective approach is using git fetch –prune to automatically remove remote-tracking branches that no longer exist on remote. This method provides automatic cleanup during fetch operations, prevents accumulation of stale references, and maintains accurate branch listings without manual intervention.
Use git fetch –prune to remove stale remote-tracking branches, configure automatic pruning, clean up local branches tracking deleted remotes.
# View all remote-tracking branches
git branch -r
# Output shows:
# origin/main
# origin/feature-1
# origin/feature-2
# origin/old-feature # This was deleted on remote but still shows locally
# Fetch and prune stale remote branches
git fetch --prune
# Output shows:
# From github.com:user/repo
# x [deleted] (none) -> origin/old-feature
# * [new branch] new-feature -> origin/new-feature
# View updated remote branches
git branch -r
# Stale branches are now removed
Configure automatic pruning:
# Enable automatic pruning for all fetch operations
git config --global fetch.prune true
# Enable for specific remote only
git config remote.origin.prune true
# Verify configuration
git config --get fetch.prune
# Output: true
# Now regular fetch automatically prunes
git fetch
Prune specific remote:
# Prune only origin remote
git remote prune origin
# Dry run to see what would be pruned without actually pruning
git remote prune origin --dry-run
# Output shows:
# Pruning origin
# URL: [email protected]:user/repo.git
# * [would prune] origin/deleted-branch-1
# * [would prune] origin/deleted-branch-2
Clean up local branches tracking deleted remotes:
# List local branches and their tracking status
git branch -vv
# Output shows:
# main abc1234 [origin/main] Latest commit
# feature-1 def5678 [origin/feature-1] Feature work
# old-feature ghi9012 [origin/old-feature: gone] Old work
# The "gone" indicates remote branch was deleted
# Delete local branches with gone remotes
git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -D
# Or use this safer version that prompts for each branch
git branch -vv | grep ': gone]' | awk '{print $1}' | while read branch; do
echo "Delete local branch $branch? (y/n)"
read answer
if [ "$answer" = "y" ]; then
git branch -D "$branch"
fi
done
Comprehensive cleanup script:
#!/bin/bash
# cleanup-branches.sh
echo "Fetching latest changes and pruning stale remote branches..."
git fetch --prune --all
echo ""
echo "Remote branches:"
git branch -r
echo ""
echo "Local branches with deleted remotes:"
git branch -vv | grep ': gone]'
echo ""
echo "Do you want to delete local branches tracking deleted remotes? (y/n)"
read answer
if [ "$answer" = "y" ]; then
git branch -vv | grep ': gone]' | awk '{print $1}' | xargs -r git branch -D
echo "Deleted local branches with gone remotes"
else
echo "Skipped deletion"
fi
echo ""
echo "Remaining local branches:"
git branch
Prune with additional options:
# Prune and fetch all remotes
git fetch --prune --all
# Prune tags as well
git fetch --prune --prune-tags
# Verbose output showing what's being pruned
git fetch --prune --verbose
# Force prune even if up to date
git fetch --prune --force
Advanced pruning scenarios:
# View which remote branches would be pruned
git ls-remote --heads origin | awk '{print $2}' | sed 's|refs/heads/||' > /tmp/remote-branches.txt
git branch -r | grep 'origin/' | sed 's|origin/||' | while read branch; do
if ! grep -q "^$branch$" /tmp/remote-branches.txt; then
echo "Would prune: origin/$branch"
fi
done
# Remove all remote-tracking branches for a remote
git branch -r | grep 'origin/' | sed 's|origin/||' | xargs -I {} git branch -r -d origin/{}
# Then fetch fresh references
git fetch origin
# Clean up reflog after pruning
git reflog expire --expire=now --all
git gc --prune=now --aggressive
Using Git aliases for common pruning tasks:
# Create helpful aliases
git config --global alias.prune-all '!git fetch --prune --all && git branch -vv | grep ": gone]" | awk "{print \$1}" | xargs -r git branch -D'
git config --global alias.cleanup '!git fetch --prune && git remote prune origin'
git config --global alias.branch-cleanup '!git branch --merged | grep -v "\*\|main\|master\|develop" | xargs -r git branch -d'
# Use aliases
git prune-all # Fetch, prune, and delete local branches with gone remotes
git cleanup # Basic fetch and prune
git branch-cleanup # Delete merged branches
Here the git fetch –prune removes remote-tracking branches that no longer exist on remote server. The –prune flag can be used with git fetch or as standalone git remote prune command. The fetch.prune configuration makes pruning automatic for all fetch operations. The git branch -vv shows local branches with tracking information including gone status for deleted remotes. The grep and awk pipeline filters branches with gone remotes for batch deletion. The –dry-run option previews pruning actions without making changes. The git reflog expire and git gc commands clean up dangling objects after pruning.
Best Practice Note:
This is the branch pruning workflow we use in CoreUI development to maintain clean repository state across our distributed team. Enable automatic pruning globally with fetch.prune config to prevent stale references from accumulating, communicate with team before deleting local branches to avoid losing work in progress, use –dry-run to preview pruning operations before executing them, and schedule regular repository maintenance including pruning, garbage collection, and reflog cleanup for optimal repository health.



