Read-only Git branch hygiene

Know what can be cleaned up before you delete it.

A repository with hundreds of stale branches has two kinds of ref in it, and they look identical in a branch list: the ones whose work is already on the default branch, and the ones holding the only copy of something. This page sorts a snapshot into both, in your browser. It never deletes anything and it never says a branch is safe to delete — it says which ones a human still has to look at.

1. Paste a snapshot

Nothing scanned yet. Load the worked example to see how it reads, or paste your own snapshot.

2. Read the queue

Waiting for a snapshot

Every row is a review item. Even review-delete-candidate is a routing label for a human queue, not permission to delete a ref.

BranchClassReview actionWhyCommits
Nothing reviewed yet.

Show the text report

    

Where a snapshot comes from

The snapshot is produced on your machine, by you, from a checkout you already have. It needs commit ancestry, which a browser cannot read — so the scanner builds the file and this page reviews it. That split is deliberate: the person reviewing the queue does not need the checkout, a Git client, or an account.

python3 src/branch_hygiene.py --repo /path/to/checkout --emit-snapshot > snapshot.json

To resolve branches against real pull-request history instead of leaving them uncertain, export your own pull requests first with your own credentials and pass them in:

gh pr list --state all --limit 500 --json headRefName,state,baseRefName > prs.json python3 src/branch_hygiene.py --repo /path/to/checkout --pr-json prs.json --emit-snapshot > snapshot.json

Then paste snapshot.json above. The scanner makes no network call of its own and has no account or API key; gh uses the credentials already on your machine. See is it safe to delete this Git branch?, or how this compares with the GitHub Branches page.

What the six classifications mean

Review, never guess. Every finding carries a non-executable review action. Ambiguity is reported as ambiguity rather than resolved into a delete list, and the CLI exits non-zero for it instead of pretending that zero means safe.
Recoverable by design. The manifest preserves branch tips and commit ids so a reviewer can keep unique work before operating Git elsewhere.
Runs where the data lives. Use a local checkout or your own CI. Repository names, branch names, commit messages, and file contents never enter an analytics service.

Common questions

Does review-delete-candidate mean the branch is cleared for deletion?

No. It means the branch's pull request was merged and its tip is inside the recorded base history, which is the strongest evidence this tool can produce from a snapshot — and it is still a routing label for a human review queue, not permission to delete a ref. Nothing on this page deletes anything, and nothing on it can.

Does exit status 0 mean every listed branch is cleared for deletion?

No. A zero exit status only means the snapshot contained no unresolved shared, moved-tip, or uncertain finding under --fail-on-risk. Every finding still carries a review_action, which is a routing label for a human review queue, not permission to delete a ref.

What does exit status 2 mean?

A human must review at least one finding classified shared, moved-tip, or uncertain before any cleanup proceeds. It never means a branch is confirmed clear for deletion — it flags exactly the cases the scanner cannot resolve on its own. On this page those are the rows counted in the headline.

Why does a branch with no open pull request show as "uncertain" instead of safe?

Without pull-request metadata there is nothing to distinguish an abandoned branch from one whose work was never proposed anywhere, so a branch that is not merged and not explicitly marked protected is reported as uncertain rather than assumed abandoned. Pass --pr-json (exported once with your team's own gh CLI credentials) to resolve branches against their actual pull-request history instead of guessing from ref state alone.

Why is a branch whose pull request merged still not a delete candidate?

Because a merged pull request only tells you that some commits landed, not that the branch still points at them. If the local tip was moved after the merge — a rebase, an amend, one more commit — the tip is outside the base history and those commits exist nowhere else. That case is classified moved-tip, and it is the one this tool exists to catch: it is indistinguishable from a clean merge in a branch list. The worked example includes one.

Does this tool delete branches or run any Git write operation?

No. It only reads refs, commit ancestry, and the JSON files you pass it. It never fetches, pushes, or deletes, and the recovery manifest it writes explicitly marks itself read-only and approval-required. This page cannot reach your repository at all.

Does repository data leave the machine it runs on?

No. The snapshot you paste is parsed and classified entirely in this browser; nothing is uploaded and there is no server to upload it to. The scanner likewise makes no network requests. The optional --usage-log and this page's counting record only an aggregate event name and count — never branch names, commit messages, repository names, or file contents.