[BUG] /diff panel runs git without cwd, so it reads the launch directory instead of the session worktree (2.1.243)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code (2.1.243)
What's Wrong?
The /diff panel runs every git command without a cwd. The git child process therefore inherits process.cwd() of the claude process, which is the directory where the CLI started.
EnterWorktree changes the session working directory that Bash, Read, and Edit use. It does not change process.cwd() of the CLI process. After EnterWorktree, the panel reads the base checkout and reports its changes. Work done in the worktree stays invisible.
Root Cause
The shared git runner sets cwd only when the caller asks for it (deobfuscated from the 2.1.243 bundle):
async function Ee(gitPath, args, opts = { timeout: …, preserveOutputOnError: !0, useCwd: !0 }) {
return z(gitPath, args, {
abortSignal: opts.abortSignal,
timeout: opts.timeout,
preserveOutputOnError: opts.preserveOutputOnError,
cwd: opts.useCwd ? c() : undefined, // <-- undefined when useCwd is absent
…
})
}
useCwd: !0 is a default parameter value. It applies only when the caller omits the options object completely. Any caller that passes its own options object and forgets useCwd silently gets cwd: undefined.
Every diff-panel call passes an options object, and not one of them sets useCwd:
b(v(), ["--no-optional-locks","rev-parse","--verify","--quiet","HEAD"], {timeout:P, preserveOutputOnError:!1, abortSignal:e})
b(v(), ["--no-optional-locks","rev-parse","--show-toplevel"], {timeout:P, preserveOutputOnError:!1, abortSignal:e})
b(v(), ["--no-optional-locks","-c","diff.relative=false","diff","--numstat"], {timeout:P, preserveOutputOnError:!1, abortSignal:e})
b(v(), ["--no-optional-locks","-c","diff.relative=false","diff",e,"--shortstat"], {timeout:P, preserveOutputOnError:!1, abortSignal:t})
b(v(), ["--no-optional-locks","ls-files","--others","--exclude-standard","--full-name"], {timeout:P, preserveOutputOnError:!1, abortSignal:t})
The string useCwd does not occur once in the whole diff-panel module. Other git call sites in the same bundle do pass it, for example:
_(b(), [...w, "diff", ...we, "HEAD"], { useCwd: !0, maxBuffer: e })
The rev-parse --show-toplevel call is the worst one. It anchors the whole panel to the repository root of the wrong directory.
Steps to Reproduce
- Start
claudein a git repository, for example/path/to/repo. - Ask Claude to work in a worktree. The session moves to
.claude/worktrees/<name>. - Confirm the move.
pwdin Bash shows the worktree path. - Edit a file in the worktree.
- Run
/diff. - Actual: the panel shows the uncommitted changes of
/path/to/repo. The worktree edit is absent. - Expected: the panel shows the uncommitted changes of
.claude/worktrees/<name>.
Starting a new claude session inside the worktree works correctly, because process.cwd() and the worktree then agree.
Suggested Fix
Add useCwd: !0 to every git call in the diff-panel module. A safer change is to invert the flag, so that cwd is applied unless a caller opts out. The current default-parameter form fails open, and any new caller repeats the bug.
Related Issues
- #65767 (closed) — same symptom in the UI diff view; this report adds the root cause.
- #78733 — file links resolve against the original project root after
EnterWorktree. - #45202 (closed) — "Open in VS Code" opens the original directory after
EnterWorktree. - #78212 — desktop diff panel shows the base repo for a hook-created worktree.
Is this a regression?
I do not know.
Environment
- Claude Code: 2.1.243 (CLI, terminal)
- OS: macOS, Darwin 25.5.0