Delete local branches that are already merged
A bash script that lists local branches fully merged into main and, if you ask, deletes them. It never touches the current branch or common long-lived branches.
After a few weeks of pull requests, git branch fills up with finished work. This script finds local branches whose commits are all contained in a base branch and removes them. By default it only shows what it would delete.
The command it builds on
git branch --merged main
That lists every local branch whose tip is reachable from main, which means deleting it loses nothing. The script filters out the branch you are on, the base branch, and main, master, and develop, then deletes the rest with git branch -d. The lowercase -d double-checks the merge and refuses if anything would be lost.
The script
#!/usr/bin/env bash
set -euo pipefail
base="main"
delete=false
for arg in "$@"; do
case "$arg" in
--delete) delete=true ;;
-*) echo "Unknown option: $arg" >&2; exit 1 ;;
*) base="$arg" ;;
esac
done
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || {
echo "Not inside a Git repository." >&2
exit 1
}
git rev-parse --verify --quiet "refs/heads/$base" >/dev/null || {
echo "Base branch '$base' does not exist locally." >&2
exit 1
}
current="$(git branch --show-current)"
protected=" main master develop $base $current "
branches=()
while IFS= read -r branch; do
case "$protected" in
*" $branch "*) continue ;;
esac
branches+=("$branch")
done < <(git branch --merged "$base" --format='%(refname:short)')
if [ "${#branches[@]}" -eq 0 ]; then
echo "No merged branches to clean up."
exit 0
fi
echo "Branches fully merged into '$base':"
printf ' %s\n' "${branches[@]}"
if [ "$delete" = true ]; then
for branch in "${branches[@]}"; do
git branch -d "$branch"
done
else
echo
echo "Dry run. Re-run with --delete to remove them."
fi
Usage
git switch main
git pull
bash git-prune-merged.sh # dry run against main
bash git-prune-merged.sh --delete # actually delete
bash git-prune-merged.sh develop # use another base branch
Pull first, so your local main knows about everything merged on the server. To also forget remote branches that were deleted on GitHub, run git fetch --prune; it only cleans your local copies of remote branch names.
What it will not find
If your team uses Squash and merge or Rebase and merge on GitHub, the commits on main are new ones, so Git does not see your original branch as merged. Those branches will not appear in the list. Check that the pull request was merged, then delete them by hand with git branch -D name.
Undo
Each deletion prints the branch’s last commit, for example Deleted branch fix/typo (was f272f0d). To bring one back, run git branch fix/typo f272f0d. If the output has scrolled away, git reflog still has the hash.
The script uses only Bash features available in the old Bash 3.2 that ships with macOS, so it runs there, on Linux, and in Git Bash on Windows.
See also
- 0033 The everyday Git workflow: status, add, commit, push, pull Git moves your changes through three places: the working folder, the staging area, and the commit history. These five commands, plus .gitignore… Beginner · Concept · Any system Article Housekeeping · Setup 15 Oct 2026
Repos in the wild
- git-extras tj/git-extras A collection of extra Git subcommands for common chores, such as summarizing a repository, deleting merged branches, and undoing commits. GitHub
History
Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.
- commitpedia-admin +3,125 chars