Remote Branch Cleanup โ Prune
Stale branches = mental clutter. Prune karo, saaf raho, productive raho.
When a remote branch is deleted on GitHub โ maybe after a PR merge โ your local remote-tracking branch (origin/feature) still exists. Git does not automatically remove it.
These are called "stale" remote-tracking branches โ they point to branches that no longer exist on the remote server.
Running git branch -r shows branches that were deleted on the server yesterday. This causes confusion: "I thought this branch was deleted?"
Stale branches also clutter tab completion and branch listings, making it harder to find the branches that actually matter.
The solution: git fetch --prune or git remote prune origin to clean up stale references.
# On GitHub, feature branch is deleted after PR merge
# But locally:
git branch -r
# origin/main
# origin/feature/done โ STALE! Deleted on GitHub but still showing locally
# Trying to checkout a stale branch
git checkout feature/done
# error: pathspec 'feature/done' did not match any file(s) known to git
# The problem: your local Git doesn't know the remote branch was deleted
# It remembers the last known state of the remotegit fetch --prune does two things at once: it downloads updates from the remote AND removes stale remote-tracking references.
Before fetching, Git checks each remote-tracking reference: "Does this branch still exist on the server?" If the answer is no, Git deletes the local reference.
git remote prune origin does the same cleanup but without fetching new data. Use it when you only want to clean up without updating.
git fetch --prune is preferred because it both updates AND cleans in one command.
Best practice: git config --global fetch.prune true โ this makes every git fetch automatically prune stale references. Set it once, forget about it.
Prune is SAFE: it only removes remote-tracking references (origin/branch), never your local branches or commits.
# Before prune: stale branches visible
git branch -r
# origin/main
# origin/feature/done โ deleted on GitHub, still showing
# origin/feature/old โ deleted on GitHub, still showing
# Run fetch with prune
git fetch --prune
# x [deleted] (none) origin/feature/done
# x [deleted] (none) origin/feature/old
# After prune: only real remote branches
git branch -r
# origin/main
# Prune without fetching (just cleanup)
git remote prune origin
# Pruning origin
# URL: https://github.com/team/project.git
# * [pruned] origin/feature/done
# * [pruned] origin/feature/old
# Set auto-prune (recommended)
git config --global fetch.prune true
# Now every git fetch automatically prunes
git config --global fetch.prune true once and forget. Every time you fetch, stale remote-tracking references are automatically cleaned up. No more manually running prune. This is one of the first things senior developers configure on a new machine.git push origin --delete <branch> deletes a branch on the remote repository. This is a server-side operation โ the branch is removed from GitHub.
GitHub also provides a "Delete branch" button that appears after you merge a pull request. Many developers use this instead of the command line.
After deleting a remote branch, your local branch still exists. And your remote-tracking reference (origin/branch) becomes stale until you prune.
Always delete remote branches after PR merge to keep the repository clean for the whole team.
Many teams enable GitHub's "Automatically delete head branches" setting โ no manual cleanup needed.
# Delete a remote branch
git push origin --delete feature/done
# - [deleted] feature/done
# Prune your local references
git fetch --prune
# x [deleted] (none) origin/feature/done
# Your LOCAL branch still exists!
git branch
# * main
# feature/done โ still here locally
# Delete the local branch (if merged)
git branch -d feature/done
# Deleted branch feature/done (was abc1234)
# Force delete (if unmerged โ be careful!)
git branch -D feature/done
# Auto-delete on GitHub:
# Settings โ General โ Pull Requests โ
# โ
Automatically delete head branchesOver time, you accumulate dozens of local branches from past PRs and experiments. Time for cleanup.
List merged branches: git branch --merged main โ these are safe to delete because their commits are already in main.
Bulk delete merged branches: git branch --merged main | grep -v "main" | xargs git branch -d
Be careful: --merged means the branch's commits are reachable from main. But if the branch has NEW commits not yet in main, -d will warn you. -D will not warn you โ it forces deletion.
Safe approach: always use -d (checks if merged) instead of -D (force delete). Let Git protect you from yourself.
Another useful pattern: git branch -vv | grep ': gone]' finds local branches whose remote tracking branch was deleted.
# List all local branches
git branch
# * main
# feature/auth
# feature/dashboard
# feature/login
# bugfix/header
# experiment โ unmerged, has important work!
# List branches merged into main (safe to delete)
git branch --merged main
# feature/auth
# feature/dashboard
# feature/login
# * main
# Bulk delete merged branches
git branch --merged main | grep -v "main\|develop\|\*" | xargs git branch -d
# Verify
git branch
# * main
# bugfix/header โ not yet merged
# experiment โ not yet merged
# Clean up tracking branches that no longer track a remote
git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -d
# Deletes local branches whose remote tracking branch was deletedAfter every PR merge, follow this cleanup routine to keep your repository spotless:
- Step 1: Delete the remote branch (or let GitHub auto-delete it).
- Step 2:
git fetch --pruneto clean remote-tracking references. - Step 3: Delete your local branch:
git branch -d feature/done. - Step 4: Switch to main and pull latest:
git checkout main && git pull. - Step 5: Start fresh:
git checkout -b feature/new-work.
With fetch.prune=true and GitHub's auto-delete, steps 1 and 2 are automatic. You just delete the local branch and move on.
# === The Post-Merge Cleanup Workflow ===
# Step 1: Delete remote branch (if not auto-deleted)
git push origin --delete feature/done
# Step 2: Clean remote-tracking references
git fetch --prune
# (automatic if fetch.prune = true)
# Step 3: Delete local branch
git branch -d feature/done
# (safe: checks if merged first)
# Step 4: Update main
git checkout main
git pull --rebase origin main
# Step 5: Start new work
git checkout -b feature/next-task
# === One-liner for local cleanup ===
# Delete all local branches that have been merged
git branch --merged main | grep -v "main\|develop\|\*" | xargs git branch -d
# === Automated setup for new machines ===
# Auto-prune on fetch
git config --global fetch.prune true
# Auto-delete remote branches on GitHub
# Settings โ General โ Automatically delete head branches
Lo kar liya โ Key Points:
- โ When remote branches are deleted, local remote-tracking references become stale โ they point to branches that no longer exist on the server
- โ git fetch --prune removes stale remote-tracking references while fetching updates โ one command does both
- โ git remote prune origin removes stale references without fetching new data โ use for cleanup-only scenarios
- โ Configure auto-prune: git config --global fetch.prune true โ set once, works forever
- โ git push origin --delete <branch> deletes a branch on the remote repository (server-side operation)
- โ git branch --merged main lists local branches safe to delete โ their commits are already in main
- โ Make cleanup automatic: enable fetch.prune and GitHub's auto-delete branches setting
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login