Usage

Run git-cleanup --help for the full option list. Every command below works with --json for machines.

CommandWhat it does
scanReport prunable / stale / kept branches (default command)
pruneDelete merged/stale branches — always asks first
prsList stale open PRs; --close closes them
sweepOne pass over every configured repo; prune by policy; one report
report-issueKeep one issue with a fixed title current on any forge
doctorDiagnose the environment: git, gh, tokens, config, remotes
backupList backup bundles, or restore branches from one
completionsPrint shell completions (bash / zsh / fish)
shell-hookPrint a shell or git hook snippet

scan — what's dead?

$ git-cleanup scan --verbose

📦 /path/to/repo
base: origin/main   HEAD: main
  STATUS  BRANCH                       TYPE    AGE   MERGED  PR              REASON
  PRUNE   feature/merged-old           local   60d   yes     merged #12      merged into base
  PRUNE   origin/feature/merged-old2   remote  50d   yes     -               merged into base
  stale   wip/abandoned                local   100d  -       closed #4        unmerged and stale
  3 prunable · 2 stale · 5 kept
  → git-cleanup prune  /  git-cleanup prune --remote to delete them

--check exits with code 2 when anything is prunable — the CI gate: git-cleanup scan --check && echo clean.

prune — delete, after asking

Candidates are grouped by risk and confirmed separately:

  1. ancestor-merged local branches (default answer yes),
  2. squash/rebase-merged local branches — content provably in a base branch (default yes; net-empty or coincidentally-matching branches are never flagged),
  3. unmerged branches matched by force rules (default no),
  4. merged/abandoned remote branches with --remote (default yes, only offered with --remote).

Deletions that lose unique commits write a git bundle first (backup list / backup restore to see and restore them). Pass --yes (or set GIT_CLEANUP_YES=1) to run non-interactively.

prs — the stale-PR automator

git-cleanup prs                        # list open PRs silent for pr.staleAfterDays (30)
git-cleanup prs --close --yes          # close them, with a comment (opt-in via config)

sweep — every configured repo, one pass

git-cleanup sweep --json                        # scan everything, machine-readable
git-cleanup sweep --report sweep-report.md      # plus a combined markdown report
git-cleanup sweep --report-issue "Cleanup" --dry-run
git-cleanup sweep --yes                         # prune per the config policy

The default mode is report — a sweep with no config deletes nothing. Pruning requires sweep.mode: "prune" in the config and the same confirmation gate as prune. See Automation for the cron setup.

report-issue — one living issue per repo

git-cleanup scan --json > report.json
git-cleanup report-issue report.md --dry-run     # rehearsal: search, no write
git-cleanup report-issue report.md               # create or update, any forge

doctor — why isn't PR tracking working?

git-cleanup doctor          # one diagnostic report with fix hints
git-cleanup doctor --json

backup — see and restore what prune saved

git-cleanup backup list
git-cleanup backup restore backup-2026-09-05T22-38-42-618Z-force.bundle

restore fetches every branch in the bundle back only if it doesn't already exist — nothing is overwritten, and it confirms first.

Exit codes

CodeMeaning
0ok
1error (bad config, non-git repo, failed deletion)
2scan --check: cleanup needed