[BUG] EnterWorktree tool does not process `.worktreeinclude` — gitignored files not copied, unlike `claude --worktree`

Open 💬 0 comments Opened Jun 24, 2026 by gghez

Bug Description

The .worktreeinclude mechanism (copy gitignored, in-repo files into a freshly created worktree) is not applied when the worktree is created by the EnterWorktree tool — i.e. when you ask Claude to "work in a worktree" during a session. The worktree is created on the correct base commit, and .worktreeinclude itself is present in the checkout, but none of the gitignored files it lists are copied in.

This is inconsistent with claude --worktree, where the same .worktreeinclude is honored. The docs list exactly three triggers for the copy:

This applies to worktrees created with --worktree, subagent worktrees, and parallel sessions in the desktop app.

EnterWorktree is described one section earlier as an equivalent way to get into a worktree ("you can also ask Claude to 'work in a worktree' during a session, and it will create one with the EnterWorktree tool"), but it is absent from the copy trigger list — and empirically the copy does not happen. Whether this is intended or not, it is a surprising inconsistency: the same end state (a worktree under .claude/worktrees/) seeds local-only files or not depending solely on how it was created.

Why this matters

.worktreeinclude exists specifically so a worktree can build/sign/run. For an Android project, local.properties (SDK path + signing config) is gitignored and required to build; for Node/Python, .env.local / .venv are required to run anything. When a worktree is created via EnterWorktree, those files are silently missing, so any build/test/run step in that worktree fails — and nothing signals why. The user reasonably assumes .worktreeinclude "worked" because the file is right there in the worktree.

Steps to Reproduce

  1. In a git repo, add a .worktreeinclude at the project root listing a gitignored, in-repo file, e.g.:

``
.env.local
``

  1. Create that gitignored file in the main checkout (echo X=1 > .env.local).
  2. Commit and push .worktreeinclude so it is on the base branch.
  3. During a Claude Code session, ask Claude to work in a worktree (this invokes the EnterWorktree tool). worktree.baseRef can be fresh or head — does not matter.
  4. Inspect the new worktree under .claude/worktrees/<name>/.

Expected Behavior

.env.local (and any other file that both matches a .worktreeinclude pattern and is gitignored) is copied into the new worktree — same as claude --worktree.

Actual Behavior

The worktree is created on the correct base (e.g. origin/HEAD with baseRef: fresh) and .worktreeinclude is present, but no listed file is copied. git status --ignored in the worktree shows nothing; the gitignored files are simply absent.

Observed in this exact situation: a .worktreeinclude listing three gitignored build/publish config files was present in the worktree, all three matched and were confirmed gitignored via git check-ignore, yet none were copied. A build that needed them would have failed.

Environment

  • Claude Code version: 2.1.187
  • OS: Linux (WSL2)
  • Worktree created via: EnterWorktree tool (session-driven, not --worktree)
  • worktree.baseRef: fresh (base resolved correctly to origin/HEAD; only the file-copy step was skipped)

Suggested Fix

Apply the .worktreeinclude copy step in the EnterWorktree tool's worktree-creation path, so it matches claude --worktree. If this divergence is intentional, the worktrees docs should explicitly state that EnterWorktree does not process .worktreeinclude and that local-only files must be copied manually.

Related

  • #69874 (worktree isolation gaps — gitignored dev files missing), #27744 (.venv/.env not available in worktrees) — both about git not checking out untracked files in general; this issue is specifically about the .worktreeinclude copy step being skipped for one creation path while working for another.
  • #28041 (.claude/ subdirs not copied with --worktree) — related "what gets seeded into a worktree" gap.

View original on GitHub ↗