Skip to content

Conversation

@khaong
Copy link
Contributor

@khaong khaong commented Feb 2, 2026

Summary

  • Fixes false positive "Shadow branch conflict detected" errors when starting Claude in a new terminal or different worktree
  • Changes shadow branch naming from entire/<commit[:7]> to entire/<commit[:7]>-<hash(worktreeID)[:6]>
  • Each git worktree now gets its own shadow branch namespace, eliminating cross-worktree conflicts

Changes

  • paths package: Added GetWorktreeID() to extract internal git worktree identifier
  • checkpoint package: Added HashWorktreeID() and updated ShadowBranchNameForCommit() to include worktree hash
  • strategy package: Updated all shadow branch operations to pass WorktreeID through the call chain
  • Removed dead code: ShadowBranchConflictError and cross-worktree conflict detection (now impossible)
  • Kept: SessionIDConflictError for same-worktree, different-session conflicts (still valid)

Test plan

  • All unit tests pass
  • All integration tests pass (with race detection)
  • Updated integration tests to use new shadow branch format
  • Updated CLAUDE.md documentation

🤖 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]> to entire/<commit[:7]>-<hash(worktreeID)[:6]>, and WorktreeID is stored in session state and threaded through checkpoint read/write/list paths.

Adds paths.GetWorktreeID() plus hashing/parsing helpers in checkpoint (HashWorktreeID, ParseShadowBranchName) and refactors callers to use branch names directly where available. Removes the old cross-worktree ShadowBranchConflictError flow and updates orphan/session cleanup matching to the new naming, alongside broad unit/integration test updates and documentation refresh in CLAUDE.md.

Written by Cursor Bugbot for commit 0854bd7. This will update automatically on new commits. Configure here.

khaong and others added 8 commits February 2, 2026 18:15
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
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>
@khaong khaong requested a review from a team as a code owner February 2, 2026 11:13
Copilot AI review requested due to automatic review settings February 2, 2026 11:13
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Entire-Checkpoint: a9eb6620b8a7
Copy link
Contributor

Copilot AI left a 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.GetWorktreeID and checkpoint.HashWorktreeID/ShadowBranchNameForCommit(baseCommit, worktreeID) to derive worktree-aware shadow branch names (entire/<commit[:7]>-<hash(worktreeID)[:6]>).
  • Propagate WorktreeID through 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 SessionIDConflictError logic.

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
@khaong khaong force-pushed the alex/fix-worktree-shadow-branch-collision branch from 86dae3d to b7ad1da Compare February 2, 2026 11:25
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
@khaong khaong force-pushed the alex/fix-worktree-shadow-branch-collision branch from 7cd9b90 to 0854bd7 Compare February 2, 2026 22:59
Copy link

@cursor cursor bot left a 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.

@khaong khaong enabled auto-merge February 2, 2026 23:40
@khaong khaong merged commit 2474647 into main Feb 2, 2026
4 checks passed
@khaong khaong deleted the alex/fix-worktree-shadow-branch-collision branch February 2, 2026 23:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants