Git Branch Staleness Analyzer
Audit Git branch inventories locally with age, merge, protection, ahead/behind, and gone-upstream signals before deleting stale branches.| {{ header }} | Copy |
|---|---|
|
{{ emptyResultTitle(tab.key) }}
{{ emptyResultNote(tab.key) }}
|
|
| {{ cell.value }} {{ cell.value }} |
Introduction
Busy Git repositories collect branch names long after the work behind them has moved on. A feature branch may still hold unmerged commits, a hotfix branch may be kept for a release train, and an experiment branch may have been abandoned after the remote copy was deleted. Branch staleness is the review of those names against the repository's current cleanup policy, not a Git status that can be read from age alone.
A branch is only a movable reference to a commit, so deleting the wrong one can remove a useful pointer even when the commits still exist elsewhere for a while. Cleanup work therefore needs several clues at once: when the branch last changed, whether it was merged, whether it is ahead of or behind its upstream, whether the upstream still exists, and whether the name belongs to a protected branch pattern.
- Last commit age
- How many whole days have passed between the branch's last known commit date and the review date.
- Ahead and behind
- How many commits the branch has that its upstream does not, and how many upstream commits it has not received.
- Merged branch
- A branch whose tip has already been incorporated into the comparison target or is marked that way in the inventory.
- Protected branch
- A branch that should be held out of deletion workflows because it is the default branch, a release or hotfix name, or explicitly marked protected.
- Gone upstream
- Tracking evidence that the branch's recorded upstream reference is no longer present on the remote.
Different teams choose different stale thresholds. A small service team may nudge owners after a few weeks because old branches quickly fall behind a fast default branch. A platform repository with long release trains may need release and hotfix names to survive much longer. The threshold is a policy line, not proof that a branch is safe to remove.
The common mistake is treating the oldest branches as the deletion list. A 120-day release branch can be valid, while a 25-day feature branch with many unpushed commits may need immediate owner attention. A useful branch cleanup review turns raw branch data into a short queue of conversations: keep, merge, rebase, close, delete after checks, or repair missing inventory data.
How to Use This Tool:
Use one dated branch export per review. Set the repository policy first, then paste the inventory and treat the cleanup queue as owner-follow-up evidence rather than an automatic delete list.
- Enter the Repository name and Default branch. The repository label appears in the summary and exports, and the default branch is treated as protected even when the pasted rows do not include a protected flag.
- Set the Reference date to the date the branch inventory was exported. This keeps repeated reviews comparable and prevents branch ages from drifting just because the page is opened later.
- Choose the Stale threshold, then open Advanced if the cleanup policy needs a different Near-stale window, Protected branch terms, Include merged branches setting, or Merged grace window.
Protected terms can be exact names, prefixes, or wildcards. The default list keeps
main,master,release/*, andhotfix/*out of ordinary deletion workflows. - Paste a Branch inventory CSV, drop a CSV, TSV, or TXT file onto the textarea, or use Browse. Headered rows are easiest to audit; useful columns include branch, last commit date, author, merged, ahead, behind, upstream, pull request, and protected.
- Use Normalize after pasting rough text, or Load sample when you want to compare the expected row shape. The badge above the textarea should show the parsed branch-row count before you trust the result.
Files larger than 2 MiB are refused for browser-side parsing. If a rough
git branch -vvpaste has no last commit date, those rows can enter the unknown-date path until you replace them with a dated export. - Review any Check source data warning before acting on the queue. Missing or unreadable dates should be fixed in the inventory instead of guessed from branch names, pull request numbers, or memory.
- Read Cleanup Brief first, then use Branch Ledger and Cleanup Queue for branch-level follow-up. The result is ready to share when the queue rows include branch, pressure, evidence, suggested action, and owner values that match the cleanup policy you selected.
Interpreting Results:
Cleanup Brief gives the repository-level readout: visible branch count, stale and near-stale counts, protected count, hidden merged count, oldest visible branch, highest pressure branch, and queue size. It is the place to confirm whether the current settings are too broad before looking at individual rows.
Branch Ledger keeps each visible branch tied to its last commit date, whole-day age, author, tracking evidence, state, and review note. Cleanup Queue narrows that ledger to branches that need owner follow-up or data repair. The chart tabs show the same evidence visually: age against the stale rule, and ahead/behind divergence as a scatter view.
| State | What it means | How to respond |
|---|---|---|
| Protected | The branch matched the default branch, a protected term, a wildcard term, or a protected inventory flag. | Keep it out of ordinary deletion unless the protection rule is wrong. |
| Merged | The row is marked merged and is either visible by request or hidden by the default merged filter. | Confirm release, tag, and rollback needs before deleting the branch name. |
| Unknown date | The last commit date was missing or could not be parsed. | Repair the inventory instead of guessing age from branch name or memory. |
| Stale | The branch age is greater than or equal to the stale threshold after protection and merge checks. | Ask the owner to delete, merge, rebase, or state why the branch should remain. |
| Near stale | The branch is inside the configured warning window before the stale threshold. | Nudge the owner early so cleanup does not become a surprise deletion request. |
| Diverged | The branch has commits ahead and is at least 10 commits behind its upstream after higher-priority age, merge, protection, and date checks do not apply. | Ask for a rebase, close, or merge decision before age becomes the main issue. |
A high cleanup pressure score is an escalation cue, not permission to delete. Check branch protection settings, pull request status, release notes, and owner intent before removing any branch that may still be needed.
Advanced Tips:
- Keep the Reference date tied to the export, not the meeting date. A stale queue from Monday and a queue from Friday are not directly comparable if the same inventory uses different reference dates.
- Review Protected branch terms before lowering the stale threshold. A strict 30-day rule is safer when release, hotfix, and default-branch names are protected by exact or wildcard patterns.
- Use Include merged branches and Merged grace window for post-merge cleanup sweeps. Leave merged rows hidden when the review is focused on active unmerged work.
- Compare Branch Age Map with Ahead Behind Map. An old branch with no ahead commits may be a cleanup conversation, while a younger branch that is far behind and still ahead of upstream often needs owner review before age becomes the main signal.
- Export Cleanup Queue for owner follow-up, but treat branch names, owner names, pull request IDs, and tracking evidence as internal engineering records.
- Use unknown-date rows as a data-repair list. A missing last commit date should delay deletion decisions even when the branch name looks abandoned.
Technical Details:
Git can report branch relationships from several angles. Branch listing can show upstream tracking, and ref formatting can expose commit dates, short ref names, and ahead/behind counts against a chosen comparison point. Those fields answer different questions: age shows recency, merge state shows whether the tip is already reachable from a target, and ahead/behind counts show divergence from the tracked upstream.
Staleness analysis works best when the inventory is exported at one point in time. The reference date anchors the age calculation, while the stale threshold and near-stale window express repository policy. If two audits use different dates or thresholds, their queues are not directly comparable even when the branch list is identical.
Rule Core
Classification is ordered so that safety checks win before age pressure is applied. A protected branch remains protected even if it is old. A merged branch is handled before stale or divergence checks. Missing dates become a data-quality state instead of being treated as current.
| Order | Condition | State | Primary action |
|---|---|---|---|
| 1 | Protected flag, default branch, exact protected term, prefix term, or wildcard term matches the branch name. | Protected | Keep and verify that the protection policy is intentional. |
| 2 | The row is marked merged. | Merged | Delete only after release, tag, rollback, and optional grace-window checks. |
| 3 | The last commit date is missing or unreadable. | Unknown date | Add a valid date before cleanup decisions. |
| 4 | ageDays >= staleDays. |
Stale | Ask the owner to delete, merge, rebase, or state intent. |
| 5 | ageDays >= staleDays - nearWindow. |
Near stale | Nudge the owner before the stale rule trips. |
| 6 | ahead > 0 and behind >= 10. |
Diverged | Ask for a rebase or closure decision. |
Formula Core
Age is measured in whole days. Negative ages are treated as zero so a future-dated or mistyped commit date does not create a misleading negative branch age.
The cleanup pressure score ranges from 0 to 100. Protected branches receive 0 because they should not compete with ordinary cleanup candidates. Other visible branches combine age pressure, divergence, state weight, review evidence, and gone-upstream evidence.
| Component | Contribution | Interpretation |
|---|---|---|
| Age term | ageDays / staleDays * 42, clamped from 0 to 58, or 12 points when age is unknown. |
Older unprotected branches move closer to cleanup review. |
| Ahead term | 2.5 points per ahead commit, capped at 24. |
Unmerged local work raises deletion risk and owner-review priority. |
| Behind term | 0.8 points per behind commit, capped at 16. |
Branches far behind upstream are more likely to need rebase or closure. |
| State term | Stale 30, merged 18, near stale 16, diverged 14, unknown date 10, current 0. | The state changes which action should happen first. |
| Review and gone terms | Open review evidence adds 6; gone-upstream evidence adds 12. | An open review can block deletion, while missing remote tracking often points to local cleanup. |
Ahead and behind values can come from explicit columns or tracking text. A tracking value marked gone is preserved as evidence because it often means a remote branch was already removed while local branch data still needs cleanup.
Limitations and Privacy Notes:
The analysis depends on the inventory you provide. It does not fetch live repository data, inspect pull requests directly, or verify branch protection rules against a hosting provider. A stale or incomplete export can therefore produce a stale or incomplete queue.
Branch text and browsed files are parsed in the browser. Downloaded CSV, DOCX, chart images, and JSON can include repository names, branch names, owner names, review IDs, and tracking evidence, so treat them as internal engineering records.
Worked Examples:
These cases show how the same branch age can lead to different follow-up depending on protection, merge state, and data quality.
Old unmerged feature
A branch last committed on 2026-01-12 with a Reference date of 2026-05-01 is 109 days old. With a 45-day Stale threshold, the Branch Ledger marks it stale and the Cleanup Queue should ask the owner to delete, merge, or rebase. If the row is also ahead of upstream, owner confirmation should happen before deletion.
Release branch held by policy
release/2.7 can be older than the stale threshold and still remain protected when Protected branch terms includes release/*. The Cleanup Brief counts it as protected, and age should not override a branch name that carries release or rollback policy.
Unknown date repair
A rough git branch -vv paste may include ahead/behind tracking but no last commit date. The warning reports missing or unreadable dates, and the affected rows enter the unknown-date path. Replace the rough paste with a dated branch export before using the Cleanup Queue for owner or deletion work.
FAQ:
Does stale mean safe to delete?
No. Stale means the branch crossed the configured age rule after protection and merge checks. Confirm ownership, ahead commits, open review status, and release needs before deletion.
Why are merged branches hidden by default?
Hiding merged rows keeps the active cleanup review focused on unmerged work. Turn on Include merged branches when the review is specifically about removing already merged branch names.
Why did a branch become protected?
A branch is protected when it matches the default branch, an inventory protected flag, an exact protected term, a prefix-style term, or a wildcard pattern such as release/*.
What date format should I use?
ISO dates such as 2026-05-01 are easiest to audit. Parseable timestamps also work, but ambiguous or missing dates should be fixed before branch cleanup decisions.
Glossary:
- Stale threshold
- The branch age, in days, at which an unprotected and unmerged branch becomes stale.
- Near-stale window
- The warning period before the stale threshold when owner nudges begin.
- Ahead commits
- Commits present on the branch that are not yet in its upstream reference.
- Behind commits
- Commits present upstream that the branch does not yet contain.
- Gone upstream
- Tracking evidence that the configured upstream reference no longer exists.
References:
- git-branch Documentation, Git SCM.
- git-for-each-ref Documentation, Git SCM.
- About protected branches, GitHub Docs.
- Deleting and restoring branches in a pull request, GitHub Docs.
- How to prune stale remote branches in Git, Simplified Guide.