| name | worktree-stale-local-main-ref-inflates-pr-diff |
| description | Stop a false "my PR is reverting/touching dozens of upstream files" alarm when
`git diff main...<branch>` reports far more files than your commit changed, in a
multi-worktree repo. Use when: (1) you're in a worktree at
`<repo>/.claude/worktrees/<X>/` (or any `git worktree`), (2) `git diff main...HEAD`
(3-dot) or `--stat` shows tens/hundreds of files + thousands of lines but your
actual commit (`git show --stat HEAD`) touched only a handful, (3) you're about to
panic about the `stale-base-pr-silently-reverts-upstream-content` trap or block your
own merge. Root cause: the LOCAL `main` ref is stale — it's parked many commits
behind `origin/main` (often checked out in the PRIMARY worktree, which nobody pulled),
so the merge-base of (local main, your branch) is ancient and the 3-dot diff includes
every file that landed on origin/main since. The REAL PR diff is against `origin/main`.
Verify with `git diff origin/main...HEAD --stat` (after `git fetch`) and
`gh pr view <N> --json files`. Sibling of git-diff-2dot-vs-3dot-merge-safety
(operator semantics) and worktree-outer-ls-mistaken-for-main-state (stale state via ls).
Also fires when a CODE-REVIEW SUBAGENT claims your PR "carries unrelated code / a
subsystem you didn't author" — same stale-local-main root cause; the authoritative
check is `gh pr diff <N> --name-only` (the reviewer likely read the full-file context
and mistook already-merged code for this PR's hunks).
|
| author | Claude Code |
| version | 1.1.0 |
| date | "2026-06-23T00:00:00.000Z" |
| disable-model-invocation | true |
Worktree: a stale local main ref inflates git diff main...branch
Problem
In a multi-worktree repo, git diff main...<your-branch> (or --stat) reports
far more files and lines than your commit actually changed — e.g. 92 files /
8,000+ insertions when your one commit touched 6 files. The instinct is to panic
that your PR is silently reverting or re-touching a pile of upstream work (the
stale-base-pr-silently-reverts-upstream-content trap) and to block your own
merge or demand a rebase. Almost always, nothing is wrong with the PR — the
local main ref is stale.
Context / Trigger Conditions
All of:
- You're working inside a git worktree (
git rev-parse --is-inside-work-tree;
path contains .claude/worktrees/<name>/ or git worktree list shows 2+ paths).
git diff main...HEAD --stat (3-dot) shows tens/hundreds of files, but
git show --stat HEAD (your actual commit) shows only a few.
- You branched off what you thought was current
main, and gh pr view <N>
reports the PR as mergeable: MERGEABLE / mergeStateStatus: CLEAN.
Why it happens: main...branch (3-dot) diffs from the merge-base of the two
refs. The merge-base uses your LOCAL main ref. In a multi-worktree setup the
local main ref is whatever the primary worktree last checked out / pulled —
frequently many commits behind origin/main because sibling sessions merge via
GitHub (squash) and nobody runs git pull on the parked primary checkout. So the
merge-base is ancient, and the 3-dot diff includes every file that landed on
origin/main since that old point — none of which your branch is actually
reverting. (This is the REF being stale, distinct from
git-diff-2dot-vs-3dot-merge-safety, which is about 2-dot-vs-3-dot operator
semantics against a correct origin/main.)
Solution
Diff against the remote ref, not the local main ref:
git fetch origin main -q
git diff origin/main...HEAD --stat
git rev-list --count HEAD..origin/main
git rev-list --count origin/main..HEAD
git merge-base --is-ancestor <your-branch-base-sha> origin/main && echo "clean base"
gh pr view <N> --json files -q '.files[].path'
gh pr view <N> --json mergeable,mergeStateStatus
If git show --stat HEAD matches gh pr view <N> --json files (your handful of
files) and the PR is MERGEABLE / CLEAN, the 92-file main...branch number was a
pure local-ref artifact — proceed. Do not rebase, do not block.
Don't bother fixing the local main ref from inside the worktree — you usually
can't (git checkout main fails: "main is already used by worktree at ").
Just diff against origin/main; that's the ref that matters for the PR anyway.
Verification
git show --stat HEAD file count == gh pr view <N> --json files count.
git diff origin/main...HEAD --stat shows only your files (small).
gh pr view <N> → mergeStateStatus: CLEAN.
git merge-base --is-ancestor <base-sha> origin/main returns 0 (your base is on
origin/main's history → the squash/merge won't revert upstream).
Example
Worktree chatbot, one feature commit touching 6 files. git diff main...HEAD --stat
→ 92 files, 8,381 insertions (TM v2/v3 + v7 analysis from other sessions). Alarm:
"is my PR reverting all of that?" Checks:
git show --stat HEAD → exactly 6 files. ✓
git fetch origin main then git rev-list --count HEAD..origin/main → 1 (just
the sibling docs commit that added my own prompt file), origin/main..HEAD → 1.
git merge-base --is-ancestor 9fd95c95 origin/main → 0 (clean ancestor).
gh pr view 1019 --json files → the same 6 files; mergeStateStatus: CLEAN.
Conclusion: the 92-file number was the stale local main ref (parked far behind
origin/main in the primary worktree). PR was clean. Merged without rebase.
Notes
- The cheap falsification is always
git show --stat HEAD vs gh pr view <N> --json files. If those two agree and are small, the 3-dot main...branch number is noise.
git fetch first — without it, even origin/main is whatever you last fetched.
- This is the inverse worry of a real stale-base revert: here the diff OVER-reports
(local base too OLD); the real revert trap (
stale-base-pr-silently-reverts-upstream-content)
is when your branch's content actually overlaps and overwrites a merged upstream
edit. Distinguish by checking gh pr view --json files (does it list the upstream
files?) + reading the actual hunks, not the 3-dot file count.
Variant — a code-review subagent flags "unrelated code riding along"
Same root cause, different messenger. A dispatched code-reviewer ran gh pr diff <N>
on a 1-commit PR (resolver fix touching 2 files) and reported that the PR also carried
"a conversation-export trace subsystem you didn't review" — because it read the full
file chatbox_tools.py (whose trace code was already on origin/main from prior merged
PRs) and conflated that ambient context with the PR's hunks. The author's own
git diff main...branch (stale local main) seemed to corroborate it.
Don't act on the reviewer's scope claim — falsify it first:
git fetch origin main -q
git log origin/main..<branch> --oneline
gh pr diff <N> --name-only
gh pr diff <N> | grep -E '^\+def |^\+class '
If --name-only lists only your files and git log origin/main..<branch> is your single
commit, the "riding along" subsystem is pre-existing code the reviewer read for context —
proceed. The reviewer's substantive findings on your real hunks still stand; only its
scope claim is the artifact.
See also
git-diff-2dot-vs-3dot-merge-safety — 2-dot vs 3-dot operator semantics (assumes a
correct origin/main); this skill is about the local main ref being stale.
worktree-outer-ls-mistaken-for-main-state — same stale-local-state family, via ls.
stale-base-pr-silently-reverts-upstream-content — the genuine revert trap (the
thing this false alarm makes you fear); rule it out via the file list + hunks.
gh-pr-merge-worktree-checkout-trap / session-handoff note — why git checkout main
/ --delete-branch fail from a worktree.