* fix(workspace-worktree): restore re-attaches existing branch instead of recreating with -b Restoring a session whose worktree directory was cleaned up but whose branch still existed locally would 422 with `fatal: a branch named <X> already exists`. The recovery path in `restore()` unconditionally fell through to `git worktree add -b`, even though `destroy()` deliberately preserves session branches so the user's commits aren't lost. When the local branch already exists, restore now clears any stale worktree registration at the target path and retries `git worktree add <path> <branch>` (no -b/-B). The existing -b fallback is preserved verbatim for the case where the local branch is genuinely missing (only the remote ref exists). -B is intentionally not used — it would force-reset the branch back to the base ref and silently discard the session's commits, which is the opposite of restore's intent. Test coverage: - 6 new unit tests covering the recovery path, cleanup tolerance, error propagation, and "no -b/-B" invariants - 2 updated existing unit tests (now mock the new refExists check) - 2 new integration tests exercising real git: branch preservation on clean restore, and recovery from a dirty teardown that left a stale registry entry Closes #1741 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(workspace-worktree): explicitly create main branch in restore integration tests CI runs git with a different `init.defaultBranch` than the local dev environment, so the bare clone has no `main` branch when the test attempts to push. Mirror the existing tests in this file (which also call `git switch -c <branch>` before the first commit). Fixes integration-test failures on PR #1742. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(workspace-worktree): rmSync stale workspace dir before retry Follow-up to the previous commit on this branch. The recovery path cleared the git worktree registry but didn't touch the filesystem, so when restore was triggered by a stale junk directory at the workspace path (workspace.exists() returns false because rev-parse fails on a non-working-tree dir), the retry would fail with the same error: fatal: '<workspacePath>' already exists Replace the inline `worktree prune` cleanup with a call to the existing `clearStaleWorktreePath()` helper, which handles all three states: - dir gone → no-op - dir present and not registered → rmSync - dir present and still registered after prune → throws (safety: never delete a registered worktree) This mirrors how create() already handles the same stale-state cases upfront via clearStaleWorktreePath at the top of its flow. Test coverage: - 1 new unit test: rmSyncs a stale workspace directory before retry - 1 new unit test: refuses to rmSync a still-registered worktree dir (data safety — error must propagate, not be swallowed) - 1 new integration test on real git: dir physically present as non-working-tree leftover, restore must rmSync it before retry, and the session commit must survive Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(workspace-worktree): extract restore helpers, drop redundant prune Addresses review feedback on PR #1742: 1. Extract two named helpers, reattachExistingBranch and createBranchFromBase, so restore()'s catch block reads as the bifurcation it actually is — 2 lines per branch, no nested try/catch hierarchy. Behavior is unchanged. 2. Drop the redundant `worktree prune` that ran inside the recovery path (via clearStaleWorktreePath). The entry-point prune in restore() is sufficient. reattachExistingBranch now inlines the existsSync + isRegisteredWorktree + rmSync sequence directly, keeping the data-safety guard ("refuse to rmSync a registered worktree") intact but skipping the second prune call. The catch block shrinks from ~46 lines to 12 (the rest moves into the helpers, where the docstrings can explain WHY each branch exists without cluttering the call site). Tests: same 64 unit + 13 integration tests still pass — the mock sequences in the recovery-path tests no longer expect a second prune call, since the new code doesn't make one. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(workspace-worktree): address Copilot review on PR #1742 Two real concerns flagged in inline review: 1. isRegisteredWorktree did strict string equality on paths. If `workspacePath` was passed in a non-canonical form (trailing slash, ".." segments) and git reported the canonical path, the check would false-negative — and the subsequent rmSync in cleanupStaleWorkspacePath would silently delete a still-registered worktree (data loss). Fix by resolve()-normalizing both sides before comparison. 2. createBranchFromBase (the "branch missing locally" recovery path) skipped the stale-path cleanup that reattachExistingBranch did. So if `workspacePath` had a stale dir AND the branch was missing, `git worktree add -b ...` would fail with the same "<path> already exists" error this PR was fixing for the re-attach case. Fix by factoring the cleanup into cleanupStaleWorkspacePath, called from both helpers. Test coverage: - Unit: path normalization safety — workspacePath with trailing slash vs canonical registered path must still throw "still registered" (proves rmSync is NOT called) - Unit: createBranchFromBase clears stale dir before -b add - Integration: branch missing locally + stale dir at workspacePath → restore must clean dir AND recreate branch from origin (commit preserved end-to-end on real git) Existing 2 "branch missing" tests updated to mock the new cleanup calls in createBranchFromBase. 66 unit tests + 14 integration tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| README.md | ||
| config.json | ||
| native-windows-support.md | ||
| restore-preserves-existing-branch.md | ||
README.md
Changesets
Hello and welcome! This folder has been automatically generated by @changesets/cli, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it in our repository
We have a quick list of common questions to get you started engaging with this project in
our documentation