Skip to content

hiroxy/git-prune-branches

Repository files navigation

git-prune-branches

Test Status

A robust and safe Bash script to prune merged or empty Git branches locally and on remotes.

Key Features

  • Safety First: Defaults to dry-run mode. Never deletes anything without explicit consent.
  • Pattern Matching: Supports glob patterns (*, ?, []) for branch protection and explicit deletion.
  • Interactive Mode: Select branches to delete using an interactive index-based interface.
  • Smart Detection: Detects merged, squash-merged, and cherry-picked branches using commit history, content hashes (patch-id), and tree-hash comparisons. It accurately identifies squash-merges even if the default branch has advanced with other commits.
  • Worktree Aware: Prevents deletion of branches currently checked out in any Git worktree.
  • Batch Deletion: Optimizes performance by deleting multiple remote branches in a single git push command.

Requirements

  • Git: Version 2.23.0 or later recommended.
  • Bash: Version 4.3 or later (required for associative arrays and namerefs).

Platform-Specific Notes

  • macOS: The default Bash bundled with macOS is outdated (version 3.2). You must upgrade bash using Homebrew:
    brew install bash
  • Linux: Most modern distributions come with a compatible Bash version pre-installed.
  • Windows: Use Git Bash or WSL2.

Usage

./prune-branches.sh [options]

Primary Options

Option Description Scope / Default
-m, --delete-merged Delete merged branches. local, remote, both (default: local)
-e, --delete-empty Delete branches with no commits relative to the default branch (includes fast-forward merged). local, remote, both (default: local)
-i, --interactive Enable interactive selection interface. -
-n, --dry-run Preview deletions without performing them (default behavior). -

Manual Deletion

Option Description Format
-d, --delete <list> Explicitly delete branches matching glob patterns. Each branch is verified if it is clean for safety. Space-separated list (e.g., feature/*).

Configuration & Protection

Patterns to protect branches from deletion can be defined across multiple sources. All patterns are combined into a single protection list:

Source Description Format
.prune-branches-protect Project-root configuration file. One pattern per line. Supports # comments (including inline) and empty lines.
PRUNE_BRANCHES_PROTECT Environment variable. Space-separated list of patterns.
-p, --protect <list> Command-line option. Space-separated list (quote if multiple).

Branch Matching Rules

Whether defined in a file, environment variable, or CLI option, patterns are matched against branch names using the following rules:

  • Pattern without remote prefix (e.g., release/*): Matches both local branches (release/v1) and remote branches (origin/release/v1).
  • Pattern with remote prefix (e.g., origin/feature/*): Matches only the specified remote branch. The corresponding local branch will NOT be protected by this pattern.

Example .prune-branches-protect:

# Always protect development and release branches
develop
release/*

# Protect a specific remote-only branch
origin/experimental-long-term # Inline comments are supported

Advanced Options

Option Description Default
-r, --remote <name> Specify the remote repository to use. Auto-detected (prioritizes origin)
-w, --worktree Delete associated worktrees when deleting local branches. -

Interactive Mode

When running with -i or --interactive, the script displays a numbered list of candidates to be able to select which branches to delete:

Branches that can be deleted
┌───┬─────────────────────┬────────────────┬──────────────────────────────────┐
│ # │ Last Commit Date    │ Last Committer │ Branch/Worktree Name             │
├───┼─────────────────────┼────────────────┼──────────────────────────────────┤
│ 1 │ 2026-02-15 12:00:00 │ Committer 1    │ local(merged):    feature/login  │
│ 2 │ 2026-02-15 13:00:00 │ Committer 2    │ local(picked):    feature/logout │
│ 3 │ 2026-02-15 14:00:00 │ Committer 1    │ remote(squashed): fix/deletion   │
│ 4 │ 2026-02-15 15:00:00 │ Committer 3    │ remote(empty):    fix/something  │
└───┴─────────────────────┴────────────────┴──────────────────────────────────┘
Enter the indices of the branches to delete (e.g., '1,2,5-7'),
or enter 'all' to delete all shown branches.
Press return or enter 'q' to quit without deleting anything.

Selection: 

You can specify indices using the following conventions:

Input Description
1,3,5 Only items 1, 3, and 5.
1-5 Range of items.
-5 From index 1 to 5 (shorthand).
10- From index 10 to the end (shorthand).
all Select all candidates.

License

Copyright © 2025-2026 Hiroshi Muramatsu. Distributed under the MIT License. See the LICENSE.md file for details.

About

A shell script to delete already merged or empty branches

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages