| name | full-branch-cleanup-and-worktree-hygiene |
| description | Track all dirty/untracked workspace-hub changes, merge stale branches into main, clean remote/local branches, and remove stale worktrees while preserving tracked nested gitlinks. |
| version | 1.0.0 |
| author | Hermes Agent |
| tags | ["git","branch-cleanup","worktree","workspace-hub","merge-hygiene"] |
Full Branch Cleanup and Worktree Hygiene
Use when the user asks to:
- track all untracked files/changes
- merge work to origin/main
- merge all branches to
main
- clean stale local/remote branches and worktrees
This is a high-side-effect workflow. It is appropriate only when the user explicitly authorizes broad branch cleanup.
Core sequence
-
Start from a live inventory:
git status --short --branch
git branch -vv
git branch -r
git worktree list --porcelain
git ls-remote --heads origin
-
Track dirty changes before branch deletion.
- Commit root dirty/untracked files in a broad sync commit if the user asked to track all changes.
- If a dirty path is itself a nested git repo/worktree/submodule, inspect it separately first.
-
Preserve nested gitlinks correctly.
-
Merge current integration/feature branches to main.
-
Resolve stale-branch conflicts conservatively.
-
Push and verify remote state.
-
Delete merged remote branches.
-
Remove stale worktrees before deleting local branches.
- Worktrees block branch deletion.
- Remove stale worktrees with
git worktree remove -f <path>.
- Retain intentional tracked gitlinks/nested repos unless separately approved.
- If there are dozens of worktrees, the removal loop may exceed tool/terminal timeouts. Treat timeout as partial progress: re-run
git worktree list --porcelain, continue removing the remaining paths, then git worktree prune.
- If
git worktree remove reports a missing .git file for a stale path, run git worktree prune and re-check before attempting manual filesystem cleanup.
- Run
git worktree prune afterward.
-
Delete merged local branches.
current=$(git branch --show-current)
for b in $(git for-each-ref --format='%(refname:short)' refs/heads); do
[ "$b" = "$current" ] && continue
if git merge-base --is-ancestor "$b" main; then
git branch -D "$b"
fi
done
-
Write a cleanup handoff and commit it.
Include final branch/worktree state, retained gitlinks, merged branches, deleted remote branches, conflict-resolution choices, and next-session notes.
Final verification checklist
Expected full-cleanup end-state:
git status --short --branch
git branch -a
git worktree list
git ls-remote --heads origin
Also verify no local branch has unique commits left:
python - <<'PY'
import subprocess
for b in subprocess.check_output(['git','for-each-ref','--format=%(refname:short)','refs/heads'], text=True).splitlines():
if b == 'main':
continue
ahead = subprocess.check_output(['git','rev-list','--right-only','--count',f'main...{b}'], text=True).strip()
print(b, ahead)
PY
Pitfalls
- Do not remove a tracked gitlink just because
git worktree list shows it as a detached worktree.
- Do not trust a failed-looking push if the error is
cannot lock ref; verify with git ls-remote.
- Do not delete unmerged remote branches without proving ancestry into
main.
- Do not let stale branch conflicts overwrite current planning indexes with older statuses.
- Do not normalize hook bypass during cleanup; prefer resolving or dropping the offending stale file.
- Auto-sync/background processes can create new dirty provider scorecards, planning markers, or handoffs immediately after a clean commit/push. Re-run
git status --short --branch after every push/merge wave; if the user explicitly asked to track all changes, commit the new dirt too before declaring the checkout clean.
- Another terminal may approve an issue during cleanup, creating approval markers and plan/index updates while your handoff is being written. Before exit, revalidate live GitHub labels plus local
.planning/plan-approved/<issue>.md, plan header, and docs/plans/README.md, then either commit the approval-state sync or document that it is already committed.