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.
Drafted with AI from official documentation. Scripts were run in a test environment and repository links verified. Awaiting a human check. Did it work for you? Last edited Outdated?
What this changes
Without --delete it only lists local branches merged into the base branch. With --delete it deletes those local branches with git branch -d. Remote branches and the current, base, main, master and develop branches are never touched.
How to undo it
A deleted branch can be recreated from its last commit: find the SHA in the output of git branch -d or in git reflog, then run git branch NAME SHA.
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.
Did this work for you?
No votes yet. Be the first.
If it did not work, the report form below tells the editors what went wrong.
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 · Explains an idea · Any system Article Housekeeping · Setup 15 Oct 2026
- 0357 Keep secrets out of git: .env files, gitignore and what to do after a leak Load passwords and API keys from an untracked .env file, commit a safe .env.example instead, catch mistakes before they are pushed, and… Beginner · Step by step · Any system Article Housekeeping · Secrets & access 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.
- Dominik +3,125 chars