feat: add worktree management commands, per-worktree trunks, and worktree-aware filtering#1221
Open
ed-irl wants to merge 2 commits into
Open
feat: add worktree management commands, per-worktree trunks, and worktree-aware filtering#1221ed-irl wants to merge 2 commits into
ed-irl wants to merge 2 commits into
Conversation
2 tasks
Collaborator
Author
|
This change is part of the following stack: Change managed by git-spice. |
464d594 to
4dfd1a1
Compare
abhinav
pushed a commit
that referenced
this pull request
Jun 7, 2026
…ws (#1227) ## Summary - `TestRebase_interactiveRetryPreservesTerminal` flakes on Windows because the test relies on a goroutine sleeping 20ms before removing a fake `.git/index.lock`. On Windows runners the scheduler doesn't always release the goroutine before the retry path runs — when it doesn't, the test sees the lock still present and fails. - Replace the goroutine + sleep with atomic lock removal in the first mock call. The lock is removed *before* the mock returns the lock-conflict error, so when the retry path executes there is no timing dependency to lose. ## Before ```go go func() { time.Sleep(20 * time.Millisecond) _ = os.Remove(lockPath) }() mockExec.EXPECT(). Run(gomock.Any()). DoAndReturn(func(cmd *exec.Cmd) error { _, _ = fmt.Fprintln(cmd.Stderr, "fatal: Unable to create '.git/index.lock'") return &exec.ExitError{} }) ``` ## After ```go mockExec.EXPECT(). Run(gomock.Any()). DoAndReturn(func(cmd *exec.Cmd) error { // Remove the lock before returning the lock-conflict // error so the retry path observes a clean state. _ = os.Remove(lockPath) _, _ = fmt.Fprintln(cmd.Stderr, "fatal: Unable to create '.git/index.lock'") return &exec.ExitError{} }) ``` No sleep, no goroutine, no race. ## Why this matters The flake masked CI on multiple unrelated PRs in the current stack (e.g. #1221), wasting workflow runs and obscuring real failures. Fix is independent of any feature work. ## Test plan - [x] `go test -run TestRebase_interactiveRetryPreservesTerminal -count=10 ./internal/git/` — 10/10 passing locally - [x] Verify on Windows CI runner once this lands
4dfd1a1 to
77feb3f
Compare
897f5d4 to
d5d3334
Compare
d5d3334 to
b54686b
Compare
Introduces restack.Options{AutoResolve} and threads an opts *Options
parameter through the high-level restack entry points (RestackBranch,
RestackStack, RestackDownstack) and the merge/sync RestackHandler
interfaces, with all current callers passing nil.
This is foundational plumbing for the restack auto-resolve feature.
Landing it on a branch below the consuming stacks lets every branch
inherit the 3-arg signature, rather than the signature change living
on a branch parallel to its callers.
When a user merges a stack by pushing the stack tip directly to trunk on the remote (e.g., 'git push origin --force-with-lease HEAD:main'), the forge often does not report the affected change requests as merged. On the supported-forge path, repo sync therefore failed to clean up the stack, leaving each tracked branch with a stale BaseHash that later restacks would replay against trunk, causing conflicts. Run the same local-ancestor merge check the unsupported-forge path already uses as a fallback after the forge API queries: any tracked branch whose head is reachable from the new trunk hash is treated as merged, regardless of forge state. Branches with submitted change requests still attach their ChangeID for downstack history propagation; unsubmitted branches log "merged into trunk locally".
b54686b to
221cfdc
Compare
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.
Adds
gs worktree createandgs worktree list, plus the per-worktreetrunk machinery and worktree-scoped filtering they rely on.
gs worktree create <path>sets up a new Git worktree with its own localtrunk branch (named after the worktree dir, or via --trunk) that tracks
the same remote ref as the canonical trunk. Stacks created there are
based on this branch, so
repo syncand restacks in different worktreesdon't contend on a shared trunk checkout. --no-trunk preserves the legacy
detached-HEAD behavior; -b/--branch also creates a tracked branch stacked
on the worktree trunk.
gs worktree listshows each worktree with itschecked-out branch and stack.
State gains a per-worktree trunk registry (state/worktree.go): an
additive, optional store key mapping trunk-equivalent branches to their
worktree roots. Store exposes IsTrunk, TrunkFor, and WorktreeTrunks;
branch transactions and the branch graph now treat any registered
worktree trunk as a graph root, so traversals stop there and these
branches can serve as a base but cannot themselves be tracked.
The sync handler distinguishes the canonical remote trunk from the local
trunk it pulls into for the current worktree, fast-forwarding the local
trunk from the remote canonical ref.
Adds -w/--worktree to
log shortandrepo restackto scope operationsto stacks with a branch checked out in the current worktree, backed by
BranchGraph.StacksInWorktree. repo restack also gains SkipCheckout so the
caller controls checkout.
Includes unit tests, test scripts, regenerated docs/help, and a changelog
entry.