-
Notifications
You must be signed in to change notification settings - Fork 125
fix: make shadow branches worktree-specific to prevent false conflicts #135
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Adds a function to extract the internal git worktree identifier from the .git file in linked worktrees. For main worktrees (where .git is a directory), returns empty string. For linked worktrees, extracts the name from the .git/worktrees/<name>/ path. This identifier is stable across `git worktree move` operations, making it ideal for worktree-specific shadow branch naming. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> Entire-Checkpoint: a4a8d7d25377
Adds a function to create a short, deterministic hash from a worktree identifier. This will be used to create unique shadow branch names per worktree: entire/<commit[:7]>-<hash[:6]>. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> Checkpoint: 2bc5a4da097c
Entire-Checkpoint: 2bc5a4da097c
Updates shadow branch naming from `entire/<commit[:7]>` to `entire/<commit[:7]>-<hash(worktreeID)[:6]>` to prevent collisions between different worktrees sharing the same base commit. Changes: - Add WorktreeID field to SessionState in both session and strategy packages - Update ShadowBranchNameForCommit to take worktreeID parameter - Update initializeSession to populate WorktreeID using paths.GetWorktreeID - Update all call sites throughout the strategy package to pass worktreeID - Update tests to account for new shadow branch name format This eliminates the false positive "Shadow branch conflict detected" error that occurred when starting a new session in a different worktree at the same commit as another worktree's session. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> Entire-Checkpoint: 38346dbfe2e0
Adds WorktreeID parameter to checkpoint store APIs for worktree-specific shadow branch naming: - Add WorktreeID field to WriteTemporaryOptions and WriteTemporaryTaskOptions - Update WriteTemporary and WriteTemporaryTask to use opts.WorktreeID - Add worktreeID parameter to ReadTemporary, ShadowBranchExists, DeleteShadowBranch, and ListTemporaryCheckpoints - Add ListCheckpointsForBranch for listing by branch name directly - Update all call sites in strategy package This completes the checkpoint package integration for worktree-specific shadow branches. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> Entire-Checkpoint: a4a8d7d25377
With worktree-specific shadow branch naming (entire/<commit>-<hash>), cross-worktree conflicts are no longer possible. Each worktree gets its own shadow branch namespace, eliminating the false positive conflicts that occurred when starting Claude in different worktrees. Removed: - ShadowBranchConflictError type and handler - Cross-worktree session detection in InitializeSession Kept: - SessionIDConflictError for same-worktree, different-session conflicts - Concurrent session warning flow (checkConcurrentSessions) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> Entire-Checkpoint: 8938abb0697b
Updated all integration tests that construct or verify shadow branch names to use the new worktree-specific naming format: entire/<commit[:7]>-<hash(worktreeID)[:6]> Added helper methods to TestEnv: - GetShadowBranchName(): returns shadow branch for current HEAD - GetShadowBranchNameForCommit(hash): returns shadow branch for given commit Updated TestSessionIDConflict_ExistingSessionWithState to test same-worktree, different-session conflicts (cross-worktree conflicts are now impossible with worktree-specific branch naming). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> Entire-Checkpoint: ff4ec7be3886
Updated documentation to reflect the new shadow branch naming format: entire/<commit[:7]>-<worktreeHash[:6]> Key changes: - Shadow branches are now worktree-specific (each worktree gets its own namespace) - Different git worktrees no longer conflict on shadow branches - Concurrent session warnings only apply to sessions in the same directory Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> Entire-Checkpoint: a9eb6620b8a7
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR makes shadow branches worktree-specific to eliminate false cross-worktree conflicts and threads a stable worktree identifier through session and checkpoint handling.
Changes:
- Add
paths.GetWorktreeIDandcheckpoint.HashWorktreeID/ShadowBranchNameForCommit(baseCommit, worktreeID)to derive worktree-aware shadow branch names (entire/<commit[:7]>-<hash(worktreeID)[:6]>). - Propagate
WorktreeIDthrough session state, manual-commit strategy code paths, and checkpoint storage APIs, updating unit and integration tests plus documentation accordingly. - Remove cross-worktree shadow branch conflict handling, keeping only same-worktree
SessionIDConflictErrorlogic.
Reviewed changes
Copilot reviewed 26 out of 26 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| cmd/entire/cli/strategy/strategy.go | Removes the now-impossible ShadowBranchConflictError used for cross-worktree conflicts. |
| cmd/entire/cli/strategy/manual_commit_types.go | Extends SessionState with a WorktreeID field for worktree-aware session tracking. |
| cmd/entire/cli/strategy/manual_commit_test.go | Updates shadow branch naming expectations and adds tests for worktree-specific naming, including main vs linked worktrees. |
| cmd/entire/cli/strategy/manual_commit_session.go | Derives WorktreeID via paths.GetWorktreeID during initialization and uses it when resolving shadow branch names. |
| cmd/entire/cli/strategy/manual_commit_rewind.go | Passes WorktreeID into ListTemporaryCheckpoints and uses worktree-specific shadow branch names during rewinds. |
| cmd/entire/cli/strategy/manual_commit_reset.go | Uses current worktree’s WorktreeID to reset only that worktree’s shadow branch. |
| cmd/entire/cli/strategy/manual_commit_logs.go | Uses worktree-specific shadow branch names when reporting current and additional sessions and reading descriptions. |
| cmd/entire/cli/strategy/manual_commit_hooks.go | Wires WorktreeID into session initialization, shadow-branch migration, condensation, prompt attribution, and last-prompt retrieval; keeps only SessionIDConflictError for same-worktree conflicts. |
| cmd/entire/cli/strategy/manual_commit_git.go | Propagates WorktreeID into ShadowBranchNameForCommit, ShadowBranchExists, and WriteTemporary/WriteTemporaryTask options. |
| cmd/entire/cli/strategy/manual_commit_condensation.go | Uses WorktreeID when resolving shadow branch names during session condensation. |
| cmd/entire/cli/strategy/manual_commit.go | Maps WorktreeID between session.State and strategy SessionState. |
| cmd/entire/cli/session/state.go | Adds WorktreeID to persisted session state (backed by .git/entire-sessions/*). |
| cmd/entire/cli/paths/worktree.go | Introduces GetWorktreeID to parse the internal git worktree identifier from .git (directory vs gitdir file cases). |
| cmd/entire/cli/paths/worktree_test.go | Provides unit tests for GetWorktreeID across main worktree, linked worktrees, and error conditions. |
| cmd/entire/cli/integration_test/testenv.go | Adds helpers to compute the current worktree’s shadow branch name (for HEAD or arbitrary commit). |
| cmd/entire/cli/integration_test/subagent_checkpoints_test.go | Switches shadow branch detection in tests to the new worktree-specific naming via TestEnv. |
| cmd/entire/cli/integration_test/session_conflict_test.go | Updates conflict tests to use worktree-specific shadow names and clarifies they represent same-worktree concurrent sessions, not cross-worktree. |
| cmd/entire/cli/integration_test/manual_commit_workflow_test.go | Adapts workflow tests to validate worktree-specific shadow branch names and existence. |
| cmd/entire/cli/integration_test/manual_commit_untracked_files_test.go | Uses GetShadowBranchNameForCommit for new naming when asserting shadow branch creation. |
| cmd/entire/cli/integration_test/last_checkpoint_id_test.go | Updates cleanup expectations to the new shadow branch naming format. |
| cmd/entire/cli/hooks_claudecode_handlers.go | Removes user-facing handling of ShadowBranchConflictError; keeps only SessionIDConflictError messaging. |
| cmd/entire/cli/explain.go | Switches reachable-checkpoint discovery to list by explicit branch name via ListCheckpointsForBranch. |
| cmd/entire/cli/checkpoint/temporary.go | Adds worktree-aware hashing/naming (HashWorktreeID, ShadowBranchNameForCommit), threads WorktreeID through write/read/list helpers, and generalizes listing by branch name. |
| cmd/entire/cli/checkpoint/temporary_test.go | Tests HashWorktreeID properties and the new ShadowBranchNameForCommit behavior. |
| cmd/entire/cli/checkpoint/checkpoint.go | Extends the Store interface and write options to accept WorktreeID. |
| CLAUDE.md | Updates strategy documentation to describe worktree-specific shadow branch naming and behaviors. |
Add "Before Every Commit (REQUIRED)" section with clear checklist to prevent CI failures from skipped formatting/linting. Update Important Notes to reference the new section instead of duplicating. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> Entire-Checkpoint: a9eb6620b8a7
86dae3d to
b7ad1da
Compare
Fix issues identified by reviewers:
1. ListTemporary incorrectly parsed new shadow branch format
- Added ParseShadowBranchName() to extract commit prefix from
"entire/<commit>-<worktreeHash>" format
- BaseCommit now correctly contains just the commit prefix
2. Concurrent session state missing WorktreeID
- Added WorktreeID when creating session state for concurrent sessions
- Prevents incorrect shadow branch name construction in linked worktrees
3. ReadSessionPromptFromShadow uses old format
- Updated to accept worktreeID parameter
- Now uses ShadowBranchNameForCommit for consistent naming
4. ListOrphanedSessionStates uses old format
- Now constructs expected branch name from BaseCommit + WorktreeID
- Correctly matches sessions to their shadow branches
5. IsShadowBranch regex doesn't match new format
- Updated regex to match both old and new formats
- Pattern: ^entire/[0-9a-fA-F]{7,}(-[0-9a-fA-F]{6})?$
Also added tests for ParseShadowBranchName including round-trip tests.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Entire-Checkpoint: 4a8cc61ef902
7cd9b90 to
0854bd7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
Summary
entire/<commit[:7]>toentire/<commit[:7]>-<hash(worktreeID)[:6]>Changes
GetWorktreeID()to extract internal git worktree identifierHashWorktreeID()and updatedShadowBranchNameForCommit()to include worktree hashWorktreeIDthrough the call chainShadowBranchConflictErrorand cross-worktree conflict detection (now impossible)SessionIDConflictErrorfor same-worktree, different-session conflicts (still valid)Test plan
🤖 Generated with Claude Code
Note
Medium Risk
Touches core checkpoint/session persistence and cleanup logic; mistakes could strand or delete shadow branches or prevent rewinds, though changes are contained and covered by updated tests.
Overview
Manual-commit shadow branches are now worktree-scoped to avoid cross-worktree collisions: naming changes from
entire/<commit[:7]>toentire/<commit[:7]>-<hash(worktreeID)[:6]>, andWorktreeIDis stored in session state and threaded through checkpoint read/write/list paths.Adds
paths.GetWorktreeID()plus hashing/parsing helpers incheckpoint(HashWorktreeID,ParseShadowBranchName) and refactors callers to use branch names directly where available. Removes the old cross-worktreeShadowBranchConflictErrorflow and updates orphan/session cleanup matching to the new naming, alongside broad unit/integration test updates and documentation refresh inCLAUDE.md.Written by Cursor Bugbot for commit 0854bd7. This will update automatically on new commits. Configure here.