deadbranch
4 min read

deadbranch finds and removes stale git branches. Written in Rust, MIT-licensed, and safe by default — it only deletes merged branches, never touches protected ones, always confirms, and writes a backup of every SHA it removes.

Its headline feature is a full-screen TUI for picking branches to delete, with Vim navigation, fuzzy search, visual range selection, and a Thanos-style particle dissolution animation when branches are deleted.

sh
brew install armgabrielyan/tap/deadbranch
cargo install deadbranch
npm install -g deadbranch # or: npx deadbranch list
curl -sSf https://raw.githubusercontent.com/armgabrielyan/deadbranch/main/install.sh | sh

Pre-built binaries for Linux (glibc/musl/ARM64), macOS (Intel/Apple Silicon) and Windows are on the releases page. Completions: deadbranch completions bash|zsh|fish. The only requirements are git in PATH and being inside a repo.

Commands

sh
deadbranch list # stale branches, default older than 30 days
deadbranch list --days 60
deadbranch clean --dry-run # preview, prints the exact git commands
deadbranch clean # delete merged stale branches, with confirmation
deadbranch clean -i # interactive TUI
deadbranch stats # branch health overview

list and clean share -d/--days <N>, --local, --remote and --merged. clean adds --force (unmerged branches — dangerous), --dry-run and -y/--yes for scripts.

stats prints a repository table (all / merged / unmerged / stale / safe-to-delete, split local vs remote) and an age distribution. It covers every visible branch regardless of age, so --days only moves the stale threshold rather than hiding anything.

Interactive TUI

sh
deadbranch clean -i [--days N] [--merged] [--local] [--remote] [--force]

The flags pre-seed the filters rather than fixing them; --force unlocks unmerged branches for selection. -i cannot be combined with -y or --dry-run.

KeyAction
j/↓, k/↑Navigate
gg, GTop / bottom
Ctrl+d / Ctrl+uHalf-page down / up
Ctrl+f / Ctrl+bFull page down / up
SpaceToggle selection
VVisual range select
a / ASelect all merged / all (needs --force)
n / iDeselect all / invert
dDelete selected
/Fuzzy search by branch name
s / SCycle sort (age → branch → status → type → date → author) / reverse
m, l, RToggle merged-only, local-only, remote-only filters
?Help
q/EscQuit

What makes it nice to use:

• Vim-native — gg/G, half- and full-page scrolling, relative line numbers, and V to anchor a visual range and extend it with the cursor.
• Fuzzy search highlights the matched characters in each branch name.
• Age colouring — green under 30 days, yellow 31–90, red over 90 — so the branches worth killing stand out without reading the numbers.
• Sections — merged and unmerged branches are grouped under headers rather than interleaved.
• Snap dissolution — deletion plays a particle animation with a live progress gauge while the branches are actually deleted in the background.
• Smart confirmation — a simple prompt for safe deletions, but risky ones (unmerged, remote) require typing yes.

Mouse scrolling works too.

Safety

GuardBehaviour
Merged-only defaultunmerged branches need --force
Protected branchesmain, master, develop, staging, production are never deleted
Current branchnever deleted
WIP detectionwip/*, draft/*, */wip, */draft excluded by default
Confirmationalways prompts; remote deletions prompt again
Backupsthe SHA of every deleted branch is saved
Dry run--dry-run prints the git branch -d … commands it would run

Backups & restore

Every clean writes ~/.deadbranch/backups/<repo>/backup-<timestamp>.txt, containing ready-to-run restore commands:

sh
git branch feature/old-api abc1234def5678

Or manage them through the CLI:

sh
deadbranch backup list [--current|--repo <name>]
deadbranch backup restore feature/old-api # from the most recent backup
deadbranch backup restore feature/old-api --from backup-20250201-143022.txt
deadbranch backup restore feature/old-api --as feature/recovered
deadbranch backup stats # storage usage per repo
deadbranch backup clean --current --keep 3 # prune, keeps 10 by default

Configuration

~/.deadbranch/config.toml, edited directly or via deadbranch config show|set|edit|reset.

toml
[general]
default_days = 30

[branches]
protected = ["main", "master", "develop", "staging", "production"]
exclude_patterns = ["wip/*", "draft/*", "*/wip", "*/draft"]

KeyDescription
daysDefault age threshold
default-branchBranch used for merge detection (auto-detected if unset)
protected-branchesNever deleted
exclude-patternsGlob patterns to skip

Exclude patterns are glob-style: wip/* matches wip/experiment, */draft matches feature/draft, feature/*/temp matches feature/foo/temp, and *test* matches anything containing test.


Narrower than the general-purpose git TUIs — see lazygit for full git operations and serie for the commit graph.

Roadmap items not yet shipped: --only-mine, GitHub/GitLab PR detection, JSON/CSV output, and per-repo configuration.