Skip to content

Diff branch changes from the merge base, like a pull request - #88

Merged
danipen merged 3 commits into
mainfrom
fix-branch-diff-merge-base
Jul 23, 2026
Merged

Diff branch changes from the merge base, like a pull request#88
danipen merged 3 commits into
mainfrom
fix-branch-diff-merge-base

Conversation

@danipen

@danipen danipen commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Problem

Clicking a branch label in the Graph tab diffs forkPoint..tip — the fork point being the first parent of the branch's oldest commit. Once a branch merges its upstream back in (the update-merge a long-lived branch does to stay current), that range also contains everything the upstream did in between, and the pane counts it as the branch's own work.

Concrete case: ai-extra-features shows 42 files (+4110 −46), while its PR (#75) shows 23 files (+1447 −96). GitHub diffs from merge-base(main, tip) — the last commit both sides agreed on — so the mainline work the branch merged in is excluded.

Fix

  • getMergeBase (git read layer) + mergeBase across the IPC spine: the merge base of two commits, null for unrelated histories.
  • GraphRow.upstreamHash (pure layout): the tip of the branch this one grew from — or, when the tip was already merged away, that target just before the landing merge, the way a PR keeps comparing after it lands. Only a merge on the fork parent's chain counts as landing, so a sync merge pulling main into a child never turns the child into main's upstream.
  • openRange resolves the base to merge-base(upstream, tip) before loading files, so the pane header, the file list, and every per-file diff share the same base. Branches with no known upstream (the mainline, root chains, empty branches) keep the old behavior.

Verification

  • git diff 3e0956b..7a561eb (the resolved base) = 23 files, +1447 −96 — byte-identical to PR Add opt-in AI features: commit messages, explanations, branch names, error help #75's stats.
  • Driven visually via Playwright against the built app: ai-extra-features now shows 23 files / +1447 −96 with base 3e0956b; clicking main is unchanged; zero console errors.
  • New integration tests for getMergeBase (agreement point, own-work-only range, unrelated histories) and layout tests for upstreamHash (unmerged, merged, and the sync-merge guard).

lint, typecheck, and test all green (842 pass).

🤖 Generated with Claude Code

danipen added 3 commits July 23, 2026 12:34
getMergeBase finds the last commit two branches agreed on (null for
unrelated histories), exposed to the renderer as gitgrove.mergeBase.
The branch-changes view needs it: diffing a branch from its fork point
over-counts once the branch merged its upstream back in, while
mergeBase..tip is exactly the branch's own work — what its PR shows.
GraphRow.upstreamHash names the tip of the branch this one grew from —
or, when the branch's tip was already merged away, that target just
before the landing merge, the way a pull request keeps comparing after
it lands. Only a merge ON the fork parent's chain counts as landing, so
a sync merge that pulled main into a child branch never turns the child
into main's upstream. mergeChildOf becomes mergeChildrenOf (newest
first) to make that distinction possible.
Clicking a branch label diffed forkPoint..tip, so a branch that had
merged its upstream back in counted everything the upstream did in
between as its own changes (ai-extra-features showed 42 files where PR
#75 shows 23). openRange now refines the base to
merge-base(upstream, tip) before loading files, keeping the pane header,
file list and per-file diffs on the same base; branches with no known
upstream (the mainline, root chains) keep the old behavior.
@danipen
danipen merged commit 40f627d into main Jul 23, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant