Git Branch Staleness Analyzer
Review a dated Git branch inventory locally to find stale or diverged work, protect important names, and build a safer cleanup queue.{{ summaryHeading }}
main, release/*, hotfix/*.| Metric | Value | Status | Next action | Copy |
|---|---|---|---|---|
| {{ row.metric }} | {{ row.value }} | {{ row.status }} | {{ row.next_action }} |
| Branch | Last commit | Age | Author | Tracking | State | Review note | Copy |
|---|---|---|---|---|---|---|---|
| {{ row.branch }} | {{ row.last_commit }} | {{ row.age }} | {{ row.author }} | {{ row.tracking }} | {{ row.state }} | {{ row.review_note }} |
| Branch | Pressure | Evidence | Suggested action | Owner | Copy |
|---|---|---|---|---|---|
| {{ row.branch }} | {{ row.pressure }} | {{ row.evidence }} | {{ row.suggested_action }} | {{ row.owner }} |
{{ chartErrors.age }}
{{ chartErrors.divergence }}
Old branch names make a repository harder to read, but age alone does not make a branch disposable. A quiet release branch may still be protected, while a recent feature branch can already be risky because its upstream vanished or it contains commits that never reached the default branch. Cleanup starts with evidence about the commit graph and team policy, not a list sorted by date.
- Last-commit age
- Whole calendar days from the recorded commit date to a fixed review date.
- Ahead and behind
- Commits unique to the branch and commits present on its upstream but missing locally.
- Merged
- The inventory says the branch work has been incorporated into its comparison target.
- Gone upstream
- The tracked remote branch is no longer advertised, although the local branch can still contain useful work.
A stale threshold is a review policy. Teams with short-lived feature work may choose a few weeks; repositories with maintained release lines may allow months. The near-stale window gives owners notice before the threshold, while protected names keep default, release, hotfix, or explicitly marked branches outside ordinary deletion work.
Merge status also needs a clear reference. Git's merged test is about reachability from a chosen commit, not a general promise that a branch is safe to remove everywhere. Pull requests, tags, release procedures, worktrees, forks, and deployment references can keep a branch useful after its tip is reachable from the default branch.
A good branch audit produces conversations and checks. It identifies work to keep, rebase, merge, close, delete after confirmation, or repair in the inventory. It should never turn a heuristic score into an automatic deletion command.
How to Use This Tool:
Take one dated snapshot and apply one repository policy so ages and comparisons remain reproducible.
- Enter the Repository, Default branch, and Reference date. The reference date should match the inventory snapshot rather than today's date.
- Choose the Stale threshold and Near-stale window. The near-stale window must be between 0 and the stale threshold.
- Set Protected branch terms for exact names, prefixes, or wildcard patterns. The default branch and any row marked protected are always protected.
- Paste or load a CSV, TSV, pipe-delimited, TXT, or recognizable
git branch -vvinventory. A dated table is preferred becausegit branch -vvtext alone does not contain the last-commit date. - Choose whether to include merged branches and, if needed, set a Merged grace window. Repair duplicate names, negative divergence counts, or missing dates before acting on the queue.
- Start with Cleanup brief, then verify individual rows in Branch ledger and Cleanup queue against Git and the branch owner.
Interpreting Results:
Stale and Near stale describe age against the chosen policy, not deletion safety. Diverged is used only for a current-age branch that is ahead and at least 10 commits behind. Unknown date means the row needs repair before an age decision.
Cleanup pressure orders follow-up by age, divergence, state, open-review evidence, and a gone upstream. A higher number is a review priority, not permission to delete. Confirm reachability, unpushed commits, pull requests, worktrees, tags, release use, and owner intent with Git and the hosting service.
When merged branches are hidden, the visible counts and queue omit them, while protected and unknown-date counts still describe the complete parsed inventory where stated. Keep the same inclusion policy when comparing audit dates.
Technical Details:
Dates are interpreted as Gregorian calendar dates and reduced to whole-day serial values. Future commit dates do not produce negative age; their age is clamped to zero. Branch classification follows a fixed precedence, so protection and merge status override age, and a stale branch is not relabeled diverged.
Rule Core:
| Order | Condition | State |
|---|---|---|
| 1 | Default branch, protected term match, or protected inventory flag | Protected |
| 2 | Inventory marks the branch merged | Merged; held when age is less than a positive merged grace window |
| 3 | Last-commit date is missing or unreadable | Unknown date |
| 4 | Age is greater than or equal to the stale threshold | Stale |
| 5 | Age is greater than or equal to stale threshold minus near-stale window | Near stale |
| 6 | Ahead is greater than 0 and behind is greater than or equal to 10 | Diverged |
| 7 | No earlier rule matches | Current |
Formula Core:
Age is the non-negative difference between the review date and commit date. Pressure combines bounded contributions so no single large count can dominate the 0 to 100 result.
A is age divided by the stale threshold, multiplied by 42 and capped at 58. U is ahead commits multiplied by 2.5 and capped at 24. B is behind commits multiplied by 0.8 and capped at 16. W is the state weight: 30 stale, 18 merged, 16 near stale, 14 diverged, 10 unknown date, or 0 current. R adds 6 for an open review and G adds 12 for a gone upstream. Protected branches always receive 0.
The inventory is limited to 2 MiB. Ahead and behind must be non-negative whole numbers, dates must begin with YYYY-MM-DD, and duplicate branch names are rejected case-insensitively.
Privacy and Limitations:
Inventory text is analyzed locally and is not placed in the page URL. It may still contain private repository names, branch names, authors, and pull-request identifiers, so review exported evidence before sharing it.
- The analysis does not contact a Git remote or hosting service and cannot prove that upstream, merge, protection, or pull-request fields are current.
- A protected-name match is a local policy rule, not confirmation of a server-side branch protection rule.
- A gone upstream does not mean local commits are merged, backed up, or unwanted.
References:
- git-branch documentation, Git.
- git-for-each-ref documentation, Git.
- How to set upstream tracking for a Git branch, Simplified Guide.
- How to delete a local Git branch, Simplified Guide.