Worktree provisioning overwrites git-tracked files with the primary checkout's copies
Summary
In a Claude Code-managed git worktree, git-tracked files under a repo-tracked config directory are overwritten with the primary checkout's working copies during worktree provisioning. Immediately after the worktree is created, tracked files no longer match the worktree's own HEAD — they match the primary checkout instead. This leaves working tree ≠ HEAD for tracked files the moment a session starts.
Per the worktree docs, .worktreeinclude copies only gitignored files, and tracked files are never duplicated — so this appears to contradict documented behavior.
Environment
- Claude Code 2.1.211 (please confirm exact version applies)
- Windows 11, Git Bash / PowerShell
- Repo with tracked files under
.claude/commands/and.claude/hooks/
Expected
A freshly created worktree's tracked files equal that worktree's HEAD (from git worktree add). Nothing copies tracked files from the primary checkout.
Actual
Tracked files in the Claude-managed worktree are byte-identical to the primary checkout's copies and differ from the worktree HEAD when the primary checkout is on a different/older commit for those paths.
Evidence (observed instance)
- Worktree
HEAD, primary-checkoutHEAD, andorigin/mainwere three different commits; the primary checkout was diverged fromorigin/main(dozens of unique commits each side). - Several tracked files under
.claude/{commands,hooks}had a real content patch vs the worktreeHEAD, and each was byte-identical (same SHA-256) to the primary checkout's copy. - The primary checkout's copies were clean vs its own (older)
HEAD. - The worktree's
settings.local.jsonwas byte-identical to the primary's and used absolute hook paths pointing into the primary checkout dir — corroborating a wholesale copy of the config dir from the primary. - (Minor: a few tracked files also showed as modified in
git statusbut produced no patch vsHEAD— line-ending/index artifacts, separate nuisance.)
Isolation (git is not the cause)
A plain git worktree add <path> origin/main (no Claude session) produces a clean tracked config dir — git diff --name-only HEAD -- <tracked dirs> is empty and git status is clean. So git worktree add checks tracked files out correctly; the overwrite occurs only in the Claude Code provisioning step that runs when a session opens in the worktree.
Impact
- Any tool that reviews the working tree vs a base picks up these stale tracked files as noise. Concretely,
codex exec review --base <ref>(working-tree-scoped) emitted ~10 findings all in the stale tracked files and zero on the actual intended change. - More generally,
working tree ≠ HEADon freshly created worktrees breaks diff-based automation and confusesgit status.
Reproduction note
The overwrite is triggered by the Claude session/provisioning step (not by git worktree add), so it can't be reproduced from a plain shell. To reproduce: with a repo whose primary checkout is on an older/diverged commit for tracked config files, open a Claude-managed worktree branched off a newer commit, then inspect git diff HEAD -- <tracked config dirs> in the worktree — it will show the primary's versions.
Suggested fix
Worktree provisioning should not copy git-tracked paths (let git worktree add own them), or should copy from the worktree's HEAD rather than the primary checkout's working tree. Keep .worktreeinclude limited to gitignored files as documented.