repo-cleanup
Skill1 starsChanged 7 months agoMITView on GitHub
Use when a repo has accumulated stale worktrees, branches, or half-finished work — asked to clean up or prune branches and worktrees, tidy a repo, work out what's safe to delete, or find out what's still lying around unfinished
- Reads credentials
6 other projects use a version of this.
Adopted by
Most recently taken up by
- itgenius-au/skills-librarytheir own version, first seen Nov 1, 2026
- sreejithraman/SreeStacktheir own version, first seen Oct 27, 2026
- EJRyan89/coding-agent-skillstheir own version, first seen Oct 17, 2026
- Sassy-Dog/skillstheir own version, first seen Oct 8, 2026
- henry-1981/context-first-harnesstheir own version, first seen Apr 19, 2026
- JunMA98/Computer-science-claude-skillstheir own version, first seen Mar 11, 2026
Other versions6 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 6
- JunMA98/Computer-science-claude-skills★ 3same name
- EJRyan89/coding-agent-skills★ 2same name
- itgenius-au/skills-library★ 1same name
- Sassy-Dog/skills★ 1same name
- sreejithraman/SreeStack★ 1same name
- henry-1981/context-first-harness★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository6 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- ai-slop-auditSkill
- end-sessionSkill
- rubber-duckSkill
- status-reportSkill
- structured-debuggingSkill
The file
We split this skill into the rules it gives an agent
3 rules. 0 are common, 3 are distinctive, and 0 are very specific to this project.
0
Common
Most of the 5 edited versions we read keep these.
3
Distinctive
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 34
If a forge CLI is available, pull request state too — it resolves most ambiguity for free:
- Distinctive: line 44
Every branch and worktree lands in exactly one bucket.
- Distinctive: line 142
Reporting instead of acting: If a branch is provably in base, delete it.
“Common” is measured: kept by at least 6 in 10 of the 5 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Repo Cleanup
Rigid. Survey everything before deleting anything, and work the buckets in order — cruft, then quick wins, then the report. The classification rules and the safety rules are not optional. How much of a quick win you finish is a judgment call; what counts as deletable is not.
The two ways this goes wrong
- Deleting live work. Trust-destroying, even though the reflog usually saves you.
- Assessing everything and deleting nothing. The common failure. A tidy report that leaves forty stale branches in place has cleaned up exactly zero.
The order below avoids both: remove what is provably redundant without ceremony, then spend the remaining effort on the few things that need a person.
Step 1: Survey (read-only)
Gather the whole picture before touching anything. Nothing here modifies the repo.
base=$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|^origin/||')
base=${base:-main}
git fetch --prune origin
git worktree list
git for-each-ref --sort=-committerdate \
--format='%(refname:short)|%(upstream:track)|%(committerdate:relative)' refs/heads
git stash list
git status --porcelaingit fetch --prune only drops remote-tracking refs for branches deleted on the forge. It never touches a local branch, and it is what makes the [gone] marker below trustworthy.
If a forge CLI is available, pull request state too — it resolves most ambiguity for free:
gh pr list --state all --limit 100 --json number,title,state,headRefName,isDraftArtifact: a list of every worktree, local branch, and stash, each with its tracking state, age, and PR state if known.
Step 2: Classify
Every branch and worktree lands in exactly one bucket. Do not act until each one has a bucket.
Cruft — delete, no confirmation needed
The work is already in the base branch, or was never work at all:
- Upstream
[gone].git for-each-refprints[gone]when the remote branch was deleted — which is what a forge does on merge. Strongest single signal, and it covers the squash and rebase merges that--mergedmisses. - Merged by ancestry.
git branch --merged "$base"lists them. Reliable, but only catches true merges. Squash-merged. The content is in base under a different commit, so
--mergedwill not see it. Replay the branch tree onto the merge base and ask whether that patch already exists:mb=$(git merge-base "$base" "$b") synth=$(git commit-tree "$b^{tree}" -p "$mb" -m _) git cherry "$base" "$synth" | grep -q '^+' || echo "$b: content already in $base"git cherryprints a line per commit —-when an equivalent patch is already upstream,+when it is not. Test for the absence of+lines; the output is never empty, so an emptiness check would never fire. Both ways this test fails err toward keeping the branch: a branch with no unique content produces an empty patch and reads as+, and a squash applied onto a base that has since moved may no longer match by patch-id. Neither can cause a wrong deletion.- No unique commits.
git log --oneline "$base".."$b"is empty — the branch is a bookmark pointing at history base already has. - Worktrees whose branch is any of the above and whose
git status --porcelain --ignoredis clean. Use--ignored, not plain--porcelain. Git refuses to remove a worktree holding modified or untracked files, but ignored files are not covered by either protection: a worktree whose only contents are a gitignored.env, a local database, or a build cache reads as clean, andgit worktree removedeletes it without complaint. - Worktree registrations whose directory no longer exists —
git worktree pruneclears these.
Quick win — finish it now
Small, close to done, and nothing about it needs a decision:
- A branch whose diff is under roughly a hundred lines, whose tests pass, and which is one commit message or one push from a PR.
- A branch that is only behind base — merge forward, confirm it still builds, push.
- A stash that applies cleanly and is obviously the same work as an existing branch.
Finishing means finishing: run the tests, commit, push, open the PR. A quick win left at 90% is now a second piece of cruft.
Needs a person — report, do not act
- Unmerged commits that are not obviously superseded.
- Anything with a conflict, a failing test, or an open PR carrying review comments.
- A stash you cannot attribute to a branch.
- Anything months old with real content — age suggests abandonment, but only the author knows.
Old and abandoned is a recommendation, never an action. Present these with the evidence and the exact command, and let the human run it.
Step 3: Act, cruft first
Record every branch sha before deleting. This is the line that makes the rest safe to run:
git for-each-ref --format='%(refname:short) %(objectname)' refs/heads > branches-before.txtThen clear the cruft in one pass:
git worktree remove <path>
git worktree prune
git branch -d <branch>
git remote prune originUse git branch -d, never -D, in the cruft pass. If -d refuses, the branch was misclassified — move it to "needs a person" rather than forcing it. -D is only for a branch the human has explicitly named. Likewise git worktree remove refuses a dirty tree; do not reach for --force to get past that.
Then do the quick wins, one at a time, verifying each before starting the next.
Safety rules
- Never delete a worktree with uncommitted changes, ignored files included. If
git status --porcelain --ignoredis non-empty, it is not cruft regardless of its branch state. Commit tracked work to its own branch first, or report it. - Ignored files are the one thing here that does not come back. Git never had a copy, so there is no reflog and no sha to restore from — a deleted
.envor local database is simply gone. Git's own refusal does not cover them, which makes--ignoredin the check above the only thing standing between this skill and permanent loss. Report such a worktree and let the human clear the directory. - Never
git stash droporgit stash clear. Stashes have no reflog protection worth relying on, and the stack is shared across every worktree in the repo — the entry you drop may belong to someone else's session. Report them. - Never delete the branch you are standing on, the base branch, or a release branch, whatever the classification says.
- Never rewrite published history to make a branch look mergeable — no force-push, no rebase of anything already shared on the remote.
- Deleting a local branch is recoverable from the sha you recorded:
git branch <name> <sha>. Say so in the report, with the shas. Deleting a remote branch is not nearly as recoverable — that always needs confirmation first.
Step 4: Report
Three sections, in the order the work happened:
Removed (recoverable — git branch <name> <sha>):
- feat/old-thing a1b2c3d squash-merged, PR #41
- worktree ../wt-spike — branch gone, tree clean
Finished:
- fix/typo-in-readme pushed, PR #58 opened
Needs you:
- feat/big-refactor 31 commits, 4 months old, no PR. Delete with:
git branch -D feat/big-refactor # sha e4f5a6b
- stash@{0} "wip auth" — matches no branchState counts plainly: how many deleted, how many finished, how many left. If nothing was deletable, say that — a clean repo is a valid result, and padding the report with speculative deletions is worse than a short one.
Anti-patterns
- Reaching for
-Dor--forcewhen the safe flag refuses. The refusal is information. Reclassify instead. - Trusting
git branch --mergedalone. It misses every squash and rebase merge, which on most repos is most of them. - Surveying without fetching. Stale remote-tracking refs make merged branches look unmerged and deleted ones look live.
- Batch-deleting from a glob.
git branch | grep feat/ | xargs git branch -Ddeletes by name pattern, not by evidence. Classify each branch or leave it. - Turning cleanup into refactoring. Finishing a quick win means finishing what is there, not improving it. If it needs design work, it is not a quick win.
- Reporting instead of acting. If a branch is provably in base, delete it. That is what was asked for.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

