fix: guard mutating commands across worktrees#101
Merged
dubscode merged 1 commit intoMay 25, 2026
Merged
Conversation
Completes DUB-61
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR adds a shared “worktree mutation” preflight guard to prevent Tier 3 commands (and submit) from mutating branches that are checked out in another git worktree, avoiding mid-command git failures and messy recovery states.
Changes:
- Introduces
assertBranchesNotCheckedOutElsewhere()/findWorktreeCheckoutConflict()and standardizes the user-facing refusal + recovery hints. - Wires the shared guard into mutating commands (split/absorb/squash/fold/pop/rename/move/reorder/unlink) and into submit’s resolved push scope (when not dry-run).
- Adds real git-worktree integration coverage for each guarded command plus recovery-path assertions, and updates relevant mocks/fixtures.
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| packages/cli/test/helpers.ts | Adds withBranchWorktree() helper to create/remove sibling worktrees for integration tests. |
| packages/cli/test/commands/fold-tree.test.ts | Updates fold test expectations to match the new shared refusal wording. |
| packages/cli/src/lib/worktree-guards.ts | Adds the shared worktree conflict detection + standardized DubError refusal and recovery hints. |
| packages/cli/src/lib/fold.ts | Replaces per-command worktree checks with the shared guard for fold targets. |
| packages/cli/src/commands/worktree-guards.test.ts | New integration suite validating the guard across all DUB-61 commands using real worktrees. |
| packages/cli/src/commands/unlink.ts | Adds guard before unlink mutation side effects. |
| packages/cli/src/commands/unlink.test.ts | Extends git mocks to include listWorktreeCheckouts to support the guard path. |
| packages/cli/src/commands/submit.ts | Adds guard on plan.branches when dryRun is false, before submit side effects. |
| packages/cli/src/commands/submit.test.ts | Extends git mocks to include listWorktreeCheckouts to support the guard path. |
| packages/cli/src/commands/squash.ts | Adds guard for the current branch before squash mutation work. |
| packages/cli/src/commands/split.ts | Adds guard for the source branch before split mutation work. |
| packages/cli/src/commands/reorder.ts | Replaces bespoke reorder worktree logic with the shared guard. |
| packages/cli/src/commands/rename.ts | Replaces bespoke rename worktree logic with the shared guard. |
| packages/cli/src/commands/pop.ts | Adds guard for the current branch before pop mutation work. |
| packages/cli/src/commands/move.ts | Adds guard for all branches potentially mutated by a move (after no-op early return). |
| packages/cli/src/commands/move.test.ts | Extends git mocks to include listWorktreeCheckouts to support the guard path. |
| packages/cli/src/commands/absorb.ts | Adds guard for non-stack modes and stack-mode cross-fixup branches before mutation/journaling. |
| .reports/dub-61-qa.md | Adds QA fallback evidence documenting the safety change and test/gate results. |
| .reports/dub-61-adversarial-review.md | Adds adversarial review artifact documenting findings and verification. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
🎉 This PR is included in version 1.10.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
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.
TL;DR
Added a shared worktree mutation guard and wired it through split, absorb, squash, fold, pop, rename, move, reorder, unlink, and submit.
Why
Mutating a branch checked out in another worktree can fail mid-command and leave users in awkward recovery states.
DUB-8 introduced checkout detection for sync/restack/post-merge; DUB-61 extends that protection to the remaining mutating surfaces.
Before
After
File-by-file
packages/cli/src/lib/worktree-guards.ts
new +49 / -0
Adds the shared guard that finds the first conflicting branch checkout and throws a DubError with path-specific recovery hints.
packages/cli/src/commands/*.ts and packages/cli/src/lib/fold.ts
mod +72 / -69
Wires the guard into Tier 3 mutation targets and submit's resolved push scope before side effects.
packages/cli/src/commands/worktree-guards.test.ts
new +171 / -0
Adds real-git-worktree regression tests for every DUB-61 command and the recovery-path hint.
packages/cli/test/helpers.ts
mod +19 / -0
Adds a reusable helper for creating and cleaning up sibling worktrees in integration tests.
Where to focus review
packages/cli/src/commands: Each guard should run after the branch targets are known but before undo entries, cleanup journals, state writes, pushes, or PR mutations.packages/cli/src/commands/submit.ts: Submit should check exactly the resolved branches that would be pushed and should not block dry-run planning.packages/cli/src/lib/worktree-guards.ts: The user needs the exact other worktree path to recover safely.Test plan
Quality gates
pnpm checks- passed (Biome checked 318 files with no fixes applied.)pnpm typecheck- passed (Turbo typecheck succeeded for docs, dubstack, and dubstack-retarget-action.)pnpm test- passed (124 test files and 1354 tests passed.)Self-QA
See QA fallback evidence.
CLI self-QA for worktree-aware mutation refusal.
Acceptance criteria
The other worktree is '<path>'.; regression asserts this.Adversarial review
Iterations: 1
Remaining critical/major: 0/0
Remaining minor/nitpick: 0/0
Dependencies
Rollout
Ship as a CLI safety improvement; no migration or docs update required because command syntax is unchanged.
Commit