Worktree provisioning overwrites git-tracked files with the primary checkout's copies

Status Open
Reported on v2.1.211
Maintainer reply None cached
Activity 0 comments · opened Jul 21, 2026

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-checkout HEAD, and origin/main were three different commits; the primary checkout was diverged from origin/main (dozens of unique commits each side).
  • Several tracked files under .claude/{commands,hooks} had a real content patch vs the worktree HEAD, 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.json was 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 status but produced no patch vs HEAD — 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 ≠ HEAD on freshly created worktrees breaks diff-based automation and confuses git 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.

View original on GitHub ↗