Repository navigation
feat: add wspace sweep - remove every merged feature worktree workspace-wide - #154
Merged
Merged
Conversation
Reclaiming a merged branch was a seven-step ritual repeated per repository, and step 2 (git worktree remove) usually fails on Windows with "Filename too long", leaving the tree registered and the branch locked. Across ~40 repos that is how stale worktrees accumulate. sweep discovers linked worktrees from `git worktree list --porcelain` rather than from directory layout, so no on-disk convention is imposed, and deletes only after proving the merge offline (tree equality, empty diff, or ancestry). Those tiers are what authorise rebase/squash merges, whose commits have different SHAs than anything on the default branch and which `git branch -d` refuses. The baseline is origin/<default> when present: right after a merge the canonical checkout is usually still behind it, so proving against the local ref would refuse cleanup in exactly the case this exists for. Refusals are reported rather than fatal, matching update's conservative tone, so the exit code is non-zero only when a mutation actually broke; --strict promotes refusals. Remote branches are kept unless --delete-remote is passed. ADR-0006 records the reconciliation with ADR-0005, which removed worktree management: sweep creates and places nothing, and acts within the same read-only-worktree "safety, not management" carve-out ADR-0005 kept in update. Closes #153 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
|
This pull request introduces a new command, Here's a summary of the changes:
Reviewers should focus on the |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements #153.
What it does
wspace sweepremoves every linked worktree in the workspace whose branch isalready merged, workspace-wide, in one command — replacing a seven-step ritual
repeated per repository.
Design notes worth reviewing
Discovery comes from git, not paths. Candidates come from
git worktree list --porcelain; every entry after the first (the mainworktree) is a candidate. No directory is globbed, so no location convention is
imposed, and branch names are read from git rather than inferred from the
worktree leaf — which routinely differs (
world-id-hard-cutover,feat/frontmatter-fields).A
.gitguard comes first. Without it, a non-repo directory in therepositories tree (this workspace has
repos/worktrees/) makesgit -C <dir> worktree listwalk up and report an ancestor repo's worktrees,leaking root state into a child's sweep. There's a test for exactly this.
The proof ladder is offline. Tree equality → empty diff → zero commits ahead.
These tiers authorise rebase/squash merges, whose commits have different SHAs
than anything on the default branch and which
git branch -drefuses to delete.The baseline is
origin/<default>when that ref exists: immediately after amerge the canonical checkout is usually still behind it, so proving against
the local ref would refuse cleanup in exactly the case this exists for.
The workspace root is swept too. It is not a manifest entry, and the
motivating worktree (
worktrees/workspace/post-merge-cleanup) lives there, socheck/update's(workspace root)inclusion applies.Two gates, each
--force-overridable: merge proof, and cleangit status --porcelain(untracked included). The default branch and the mainworktree are never targets; detached worktrees are skipped.
Refusals are reported, not fatal — exit non-zero only on
FAILED, matchingupdate's conservative tone rather thancheck's stricter contract.--strictpromotes refusals.
--delete-remoteis opt-in.Purge escalation handles the Windows
Filename too longfailure thatgit worktree removecannot recover from: recursive delete → verbatim\?\path → empty-source
robocopy /MIR+ verbatimrmdir(rm -rfon POSIX), thenworktree prune. The strategy that worked is reported.Decisions taken on the issue's open questions
management" carve-out ADR-0005 point 6 deliberately kept in
update.gh pr viewtier — not implemented. The offline tiers cover therebase/squash cases, and keeping the common path network-free keeps a
workspace-wide sweep fast. Open to revisiting.
worktrees, which is where the worktree-isolation pattern leaves its residue.
wspace update, so the commands compose(
wspace sweep && wspace update) instead of overlapping.Verification
deno task cigreen: 185 passed, 0 failed. 13 new tests against real localgit repositories, following
integration_test.tsconventions.post-merge-cleanupworktree, refuses all three unmergeddocs/agents-cross-repo-guidancebranches withSKIP_NOT_MERGED, andrefuses dirty worktrees with
SKIP_DIRTY. Nothing claimedREMOVED,correctly, since nothing has merged yet.
Review focus
The two safety gates and the
origin/<default>baseline choice. Everythingelse is mechanical.