Skip to content

clean-branches

Do you have a lot of local branches that have been deleted on the remote server, but still linger in your local repository? This script helps you clean up those branches safely.

StepCommandEffect
1set -euo pipefailExit on the first error (-e), treat unset variables as errors (-u), and make pipelines fail if any element fails (pipefail).
2git fetch --pruneUpdates all remotes and removes any remote-tracking branches that have been deleted on the server (e.g., origin/feature-x).
3`git branch -vv …grep ‘gone]‘`Builds the array gone_branches: local branches whose upstream (remote-tracking) reference was just pruned and now shows “gone” in git branch -vv.
4If none foundPrints “No branches with gone upstream found.” and exits.
5Print the listEchoes the branch names so you can see what’s about to happen.
6git branch --merged vs. listSplits the “gone” branches into: merged_branches — already fully merged into HEAD (typically main) and therefore safe for git branch -d; unmerged_branches — contain commits that are not reachable from HEAD.
7Prompt to delete merged branchesFor each merged branch it runs git branch -d interactively (xargs -0 -n1 -p …). You have to press y (or n) for every deletion.
8Report unmerged branchesMerely prints them and warns they would need git branch -D (force delete) but does not delete them.

Is it safe?

  • Nothing happens unless you answer “y” at the first prompt, and then you still get a second prompt for every branch because of xargs -p.
  • It never touches the remote server — only local branch references.
  • It uses git branch -d, which refuses to delete a branch that is not fully merged into the current HEAD. In other words, even if the script’s “merged” test were wrong, Git itself will still protect you.

So, operationally, it is about as safe as such a cleanup script can be.

RiskHow it could happenMitigation / recovery
Accidental loss of a useful local branchYou approve deletion, then realise later you still needed it (e.g., for an in-progress rebase).The branch tip is still in git reflog for 90 days by default; you can git reflog, find the commit, and git branch <name> <SHA>.
False “merged” classificationVery rare, but could occur if you’re on a branch other than the usual integration branch (main) when you run the script, because git branch --merged compares against current HEAD.Run the script from your primary integration branch, or change git branch --merged to --merged main.
Remote renamed / forkedIf a teammate renamed the remote branch and pushed it elsewhere, your local branch now shows “gone” even though work continues under a new name. Deleting it means you lose the convenient reflog link to its history.Double-check the printed list before confirming; if in doubt, answer N and investigate.
Edge-case branch namesBranch names containing newlines or unusual bytes could confuse text processing (though the script is largely null-delimited).Unlikely in normal workflows; Git itself discourages such names.
Script aborts mid-wayBecause of set -euo pipefail, any unexpected error (e.g., network hiccup during git fetch) terminates the script. Nothing is partially deleted.Just re-run after fixing the root cause.

The script is a convenience wrapper around standard Git commands for pruning local branches whose upstreams have disappeared. If you review the printed branch list and confirm only what you truly want to delete — ideally while checked out on main or develop — the worst-case consequence is deleting a branch you later decide you want, which is recoverable via git reflog or by fetching it again if it still exists on a remote.