Skip to content
Commitpedia
Log in Join & edit

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?

Edit history of Delete local branches that are already merged: 1 recorded edit
Edit history · 1 edit
Type
Script
Edits
1
Editors
1
First issued
15 Oct 2026
Last edit
15 Oct 2026
Language
bash
Licence
CC0-1.0

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

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.

  1. Dominik +3,125 chars

Report a problem

Something wrong, unsafe or copied? Tell the editors.
What is wrong?