Last updated: July 2026
After a few months of PRs, git branch scrolls forever. Three cleanup levels, from cautious to automated.
1. Delete branches already merged
git checkout main
git branch --merged
Everything listed (except your current branch) is fully contained in main — safe to delete:
git branch --merged | grep -vE '^\*|main|master|develop' | xargs -r git branch -d
The grep -vE guard protects long-lived branches; -d (lowercase) refuses anything not actually merged, so this command can’t lose work.
2. Prune deleted remote branches
When branches are deleted on GitHub/GitLab after merge, your local copy still remembers origin/feature-x:
git fetch --prune
Make pruning automatic on every fetch/pull:
git config --global fetch.prune true
3. Delete local branches whose remote is gone
Squash-merged branches never show as “merged” locally, so method 1 misses them. But after pruning, git marks their upstream as gone:
git branch -vv
# feature-login a1b2c3d [origin/feature-login: gone] add login page
Delete all of those in one line:
git branch -vv | awk '/: gone]/ {print $1}' | xargs -r git branch -D
Note the capital -D — required because squash-merged branches look unmerged to git. That also means this command would delete a genuinely unfinished branch whose remote was removed, so glance at the git branch -vv output first.
Put it behind an alias
git config --global alias.cleanup '!git fetch --prune && git branch -vv | awk "/: gone]/ {print \$1}" | xargs -r git branch -D'
Now git cleanup prunes and deletes in one step.
If you delete the wrong branch
The commits survive for weeks in the reflog:
git reflog # find the tip commit of the deleted branch
git branch feature-x a1b2c3d # resurrect it
Which is the real reason branch cleanup is safe to automate: in git, deleting a branch only deletes the label, not the history.
