SuperAPI AI Directory

worktree-branch-rationalization

General & other

View repository

Updated 10-15 17:29

About this skill

worktree-branch-rationalization — collapse the sprawl, lose nothing worth keeping

Harvest first. Delete last. The canonical line plus a few protected branches is the destination.

⚠️ Critical Constraints

  • Harvest before you prune — always. Capture the best content onto a staging branch and commit it before removing any worktree or deleting any branch. Deletion is the last phase, never an early shortcut.
    • Why: a deleted branch's unmerged commits are only recoverable from reflog for a limited window; an orphaned-worktree branch may have the only copy of real work. Pruning first turns recoverable into lost.
    • WRONG: git worktree prune && git branch -D feature-x (delete, then hope it merged).
    • CORRECT: confirm feature-x is contained in staging (git branch --merged staging), then git branch -d feature-x (lowercase -d refuses to drop unmerged work).
  • Never remove a worktree with a dirty or locked working tree. Run git -C <worktree> status --porcelain first; uncommitted changes there are not in any branch.
    • Why: git worktree remove --force on a dirty tree silently discards uncommitted edits — the exact agent-swarm output you are trying to save.
  • Never touch the protected set. The default branch, release/maintenance branches, and any branch with an open PR are off-limits to deletion regardless of merge state.
    • Why: "merged into staging" is not the same as "safe to delete from origin"; protected branches may carry history other people depend on.
  • Use -d not -D as the default. Reserve -D (force) for branches you have individually confirmed are fully harvested.
    • Why: -D skips the "is this merged?" safety check; defaulting to it defeats the whole skill.

Why This Exists

Parallel-agent work multiplies worktrees and branches faster than anyone reconciles them. Each agent spins up a linked worktree on its own branch; runs end, sessions crash, branches get half-merged or abandoned. Weeks later the repo has dozens of linked worktrees — some pointing at deleted branches, some dirty, some duplicating work already on main — and a branch list nobody can reason about. Naive cleanup (git worktree prune, bulk git branch -D) is fast and destructive: it throws away the one copy of real work hiding in an orphaned worktree. This skill makes the safe path the default path: inventory everything, harvest the strongest content onto one staging branch, confirm containment, then collapse the rest.

Quick Start

# From the repo root. Inventory only — no mutations.
bash {baseDir}/scripts/audit.sh

# After reviewing the audit, run the guided rationalization (harvest → confirm → prune).
bash {baseDir}/scripts/rationalize.sh --staging rationalize/$(date +%Y%m%d)

audit.sh is read-only (run it first, every time). rationalize.sh mutates the repo and pauses for confirmation before any destructive step.

Workflow

Phase 1 — Inventory (read-only)

Build the ground truth. git worktree list --porcelain for every linked worktree; git for-each-ref refs/heads for every local branch with its upstream and last-commit date. Classify each into the categories in references/taxonomy.md: canonical, protected, active, stale, orphaned-worktree, drifted, duplicate.

Checkpoint: every worktree and branch lands in exactly one category, and the protected set is explicit and written down. Do not proceed until the inventory is complete.

Phase 2 — Harvest onto staging

Create one staging branch off the canonical tip. Walk the keep-worthy branches and dirty worktrees newest-first; bring their unique content over by cherry-pick, merge, or — for dirty worktrees — committing the working tree to a salvage branch first. Resolve conflicts in favor of the strongest variant. See references/harvest.md for the ordering rule and conflict policy.

Checkpoint: git log --oneline canonical..staging shows every piece of work you intended to keep, and the staging branch builds/tests clean.

Phase 3 — Confirm containment

For each branch you plan to delete, prove its content is reachable: git branch --merged staging lists the safe ones; for the rest, git cherry staging <branch> shows any commit not yet in staging. Anything with un-harvested commits goes back to Phase 2 — it is not eligible for deletion.

Checkpoint: the delete list contains only branches whose every commit is contained in staging (or is intentionally abandoned and recorded as such in the report).

Phase 4 — Prune (destructive, last)

Remove worktrees with git worktree remove (only after confirming clean status), then git worktree prune for stale administrative entries. Delete harvested branches with git branch -d. Reconcile worktree↔branch drift per references/drift.md. Write the report.

Checkpoint: git worktree list shows only the canonical + intentionally-kept worktrees; git branch shows the canonical line plus the protected set; the report is written.

Output Specification

Write the rationalization report to .agents/worktree-rationalization/report.md containing:

  • the pre-state counts (worktrees, branches) and the post-state counts;
  • the protected set (verbatim);
  • the staging branch name and the harvested commit list;
  • every deleted branch + worktree, with the reason and the SHA it was contained at;
  • any branch intentionally abandoned (unmerged content deliberately dropped), named explicitly.

Quality Rubric

  • No silent loss: every deleted branch is provably contained in staging OR named in the report's "intentionally abandoned" list — never neither.
  • Protected set untouched: the default, release, and open-PR branches still exist and point at the same SHAs they did before.
  • Reproducible state: after the run, git worktree list and git branch match the post-state counts recorded in the report.
  • Dirty work captured: no worktree was removed while git status --porcelain showed uncommitted changes.

Examples

47 worktrees after an agent swarm. audit.sh flags 31 as duplicates of main, 9 as orphaned (branch already deleted), 5 dirty, 2 canonical. Harvest the 5 dirty + any unique commits from the 9 orphaned onto rationalize/20260606, confirm containment, then git worktree remove the 45 non-canonical and git branch -d the harvested branches. Report records all 45.

Worktree↔branch drift. A worktree's branch was force-pushed and rebased elsewhere, so the local branch and the worktree's HEAD diverged. drift.md resolves it: salvage the worktree's unique commits to a branch, then re-point or remove. Never assume the worktree matches its named branch.

Troubleshooting

Symptom Cause Fix
git worktree remove fails: "contains modified or untracked files" dirty working tree commit to a salvage branch first, then remove; only --force after the salvage commit
git branch -d fails: "not fully merged" branch has commits not in staging go back to Phase 2 and harvest, or git cherry staging <branch> to see exactly what is missing
worktree listed but path gone stale administrative entry git worktree prune (safe — only removes bookkeeping for deleted paths)
branch shows merged but a worktree still references it drift resolve per references/drift.md before deleting

See Also

I need to… Reference
Classify each worktree/branch references/taxonomy.md
Order the harvest + resolve conflicts references/harvest.md
Fix worktree↔branch drift + naming conventions references/drift.md