Cleanup Git
Clean local git branches and worktrees after work has merged. Dry-run first. Destructive commands require user approval.
Prefer a repo-local scripts/cleanup-git.sh when the target repo ships one. If it does not, use the bundled skill script from this skill's scripts/ directory. Do not improvise destructive cleanup commands outside the script workflow.
Command
Run from anywhere inside a repository:
scripts/cleanup-git.sh
scripts/cleanup-git.sh --apply
scripts/cleanup-git.sh --apply --force
scripts/cleanup-git.sh --base <ref>
Branch Detection
The script fetches/prunes remotes, then chooses the comparison branch:
- Remote default branch from
refs/remotes/<remote>/HEAD. - Local
main,master,trunk,develop, ordev. - Remote
<remote>/{main,master,trunk,develop,dev}.
Use --base <ref> only for unusual repositories.
What It Removes
- Worktrees whose branch has a GitHub PR in
MERGEDstate, is merged into the detected base branch, or whose upstream is gone. - Local branches with the same criteria.
When gh is available, PR MERGED state is the source of truth for squash/rebase merges. Do not miss those just because git merge-base --is-ancestor fails after history rewrite. If no PR is found, or gh is unavailable, fall back to the git-based checks.
Guards
Hard guards:
- Skip the current worktree.
- Skip the current branch.
- Skip the detected base branch and common long-lived branches:
main,master,trunk,develop,dev. - Keep worktrees with uncommitted changes.
Soft guard:
- Keep items with commits ahead of the base branch.
--forceoverrides only this guard. - For merged PRs, treat only commits added after the PR head as "ahead". A squash/rebase-merged branch with no new local commits is still removable.
Workflow
- Run
scripts/cleanup-git.shand show the preview. - Read reasons literally:
remove ... (PR merged),remove ... (upstream gone),KEEP ... (dirty),KEEP ... (PR merged, N ahead — use --force). - Surface every
KEEPline as a human decision. - Ask before running
scripts/cleanup-git.sh --apply. - Use
--forceonly when the user confirms ahead commits are throwaway.
Output
GIT CLEANUP
===========
Status: PREVIEW | APPLIED | BLOCKED
Base: <ref>
Remove:
- <branch/worktree> — <reason>
Keep:
- <branch/worktree> — <reason and user decision needed>
Verification:
- <command> — pass/fail/not run
Conditional References
- gh-cli.md — read when
ghis available and PR-state detection is needed: squash/rebase merge detection, rate-limit batching, offline fallback.
Failure Handling
- Not a git repo: say so and stop.
- Base branch not found: ask for
--base <ref>. - Fetch fails during preview: report that refs may be stale.
- Fetch fails during apply: stop; do not delete with stale refs.
- Dirty worktree: keep it and ask the user what to do.
- Ahead commits: keep unless the user explicitly approves
--force.