[FEATURE] CLAUDE_CODE_BASE_REF env var should apply to all default-branch lookups, not only the per-file merge-base path

Resolved 💬 3 comments Opened May 21, 2026 by faketraveler-kr Closed May 24, 2026

Preflight Checklist

  • [x] I have searched existing requests and this feature hasn't been requested yet
  • [x] 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.

  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.

  1. 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).

  1. Open Worktree A from develop to work on a feature → branch

feature/abc. Diff panel should compare against develop.

  1. Simultaneously open Worktree B from master for a hotfix → branch

hotfix/blah. Diff panel should compare against master.

  1. 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.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗