claude-code - 💡(How to fix) Fix [FEATURE] CLAUDE_CODE_BASE_REF env var should apply to all default-branch lookups, not only the per-file merge-base path

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Root Cause

  1. Setting CLAUDE_CODE_BASE_REF via .claude/settings.local.json's env field. The env var IS correctly injected into the Claude Code process (verified by printenv CLAUDE_CODE_BASE_REF inside the session), but the diff panel ignores it because the code path it uses (DL4) doesn't check env vars. Only LF5-driven per-file diff calls honor it.

Fix Action

Fix / Workaround

Tried three workarounds, all unsatisfying:

Each workaround failed for a different structural reason; the common thread is that the default-branch resolution path that the UI uses doesn't honor the env var that other paths already do.

  1. Repo with develop (active dev), master (production sync from RB), release-branch (release branches).
  2. Open Worktree A from develop to work on a feature → branch feature/abc. Diff panel should compare against develop.
  3. Simultaneously open Worktree B from master for a hotfix → branch hotfix/blah. Diff panel should compare against master.
  4. Today, both worktrees show the same diff base (whichever origin/HEAD currently points to). To switch, I have to git remote set-head + touch config, which immediately changes Worktree A's diff too. Can't keep both.
RAW_BUFFERClick to expand / collapse

Preflight Checklist

  • I have searched existing requests and this feature hasn't been requested yet
  • This is a single feature request (not multiple features)

Problem Statement

I work in a worktree-heavy Git repo (one common dir with ~18 worktrees under .claude/worktrees/). Different worktrees naturally want to be compared against different "base" branches:

  • Worktree A: PR against develop
  • Worktree B: PR against master
  • Worktree C: PR against a release branch like release-branch
  • Worktree D: PR against a temporary integration branch Today the only mechanism that actually changes what the Claude Code desktop app's diff panel uses as the comparison base is git remote set-head origin <branch> (+ touching <commondir>/config to invalidate the in-memory cache). But this is a single shared resource in the commondir, so all worktrees see the same base. Concurrent sessions in different worktrees can't have different bases. I discovered (via binary inspection) that there's already a partial implementation of an env-var-based override — CLAUDE_CODE_BASE_REF and CLAUDE_CODE_BASE_REFS are honored by the per-file merge-base function (LF5), but the function that actually backs the diff panel (getCachedDefaultBranch / DL4 / BL) reads refs/remotes/origin/HEAD straight from disk via fs.readFile and never consults the env vars. So the mechanism appears to work but doesn't reach the UI that matters to users.

Proposed Solution

Make getCachedDefaultBranch (and the chain it sits in: BL / Hb6 / DL4) honor CLAUDE_CODE_BASE_REF and CLAUDE_CODE_BASE_REFS before falling back to the filesystem read of refs/remotes/origin/HEAD — i.e., mirror the priority order already used in LF5:

  1. CLAUDE_CODE_BASE_REFS map lookup keyed by repo
  2. CLAUDE_CODE_BASE_REF env var
  3. existing refs/remotes/origin/HEAD filesystem read
  4. main / master fallback

This would let users:

  • Drop a per-worktree .claude/settings.local.json with {"env": {"CLAUDE_CODE_BASE_REF": "<branch>"}} to scope the diff base per session.
  • Have concurrent sessions in sibling worktrees compare against different bases without git-config races.
  • Use CLAUDE_CODE_BASE_REFS JSON map for multi-repo setups where the scoping is already built in.

Rough sketch of the change:

async function DL4() { const cwd = await YG(); const repoKey = cwd ? jG9(cwd) : undefined; const envOverride = (repoKey !== undefined ? JG9().get(repoKey) : undefined) || process.env.CLAUDE_CODE_BASE_REF; if (envOverride) return envOverride; // existing filesystem-based resolution stays as the fallback ... }

It's a couple of lines and closes a gap that already exists in the code.

Alternative Solutions

Tried three workarounds, all unsatisfying:

  1. git remote set-head origin <branch> + touch <commondir>/config to invalidate the in-memory cache. Works for the diff panel, but it's a shared resource — every worktree sees the same value, so concurrent sessions with different desired bases conflict. Also pollutes git state that other tools (IDEs, gh CLI, scripts) read.

  2. Setting CLAUDE_CODE_BASE_REF via .claude/settings.local.json's env field. The env var IS correctly injected into the Claude Code process (verified by printenv CLAUDE_CODE_BASE_REF inside the session), but the diff panel ignores it because the code path it uses (DL4) doesn't check env vars. Only LF5-driven per-file diff calls honor it.

  3. PATH-based shell wrapper around git to intercept git symbolic-ref refs/remotes/origin/HEAD and return a value derived from $CLAUDE_CODE_BASE_REF. The wrapper installs cleanly and is verifiably called for many git invocations, but the diff panel never goes through it — DL4 reads the ref file directly via fs.readFile, bypassing the git CLI entirely.

Each workaround failed for a different structural reason; the common thread is that the default-branch resolution path that the UI uses doesn't honor the env var that other paths already do.

Priority

Medium - Would be very helpful

Feature Category

Configuration and settings

Use Case Example

Concrete workflow that surfaced this:

  1. Repo with develop (active dev), master (production sync from RB), release-branch (release branches).
  2. Open Worktree A from develop to work on a feature → branch feature/abc. Diff panel should compare against develop.
  3. Simultaneously open Worktree B from master for a hotfix → branch hotfix/blah. Diff panel should compare against master.
  4. Today, both worktrees show the same diff base (whichever origin/HEAD currently points to). To switch, I have to git remote set-head + touch config, which immediately changes Worktree A's diff too. Can't keep both.

With per-worktree CLAUDE_CODE_BASE_REF honored by the diff UI:

Worktree A/.claude/settings.local.json

{ "env": { "CLAUDE_CODE_BASE_REF": "develop" } }

Worktree B/.claude/settings.local.json

{ "env": { "CLAUDE_CODE_BASE_REF": "master" } }

Each session opens with the correct base, no conflict, no shared-state gymnastics.

Additional Context

Evidence is from disassembled Claude Code 2.1.139 (claude-desktop entrypoint on macOS arm64). The relevant minified identifiers:

  • BL = getDefaultBranch (no-arg variant reads via Hb6)
  • Hb6 = getCachedDefaultBranch → backs the cache → calls DL4
  • DL4 = the resolver that does fs.readFile on refs/remotes/origin/HEAD
  • LF5 = per-file merge-base function that already honors the env vars
  • JG9 / jG9 = CLAUDE_CODE_BASE_REFS map parser / repo-key resolver

The cache invalidates on watcher events for <gitDir>/HEAD and <commonDir>/config. The env-var values don't currently trigger anything; the simplest implementation would just read process.env on each cache miss, which still benefits from the existing cache.

Docs reference for env vars: https://code.claude.com/docs/en/settings#environment-variables

Versions:

  • Claude Code 2.1.139, claude-desktop entrypoint
  • macOS arm64

Closing this gap probably costs 2–3 lines and makes the env-var design self-consistent.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING