Skip to content

fix(git): resolve stale local base to remote-tracking ref#702

Merged
wesm merged 3 commits intomainfrom
fix/branch-review-bug
May 7, 2026
Merged

fix(git): resolve stale local base to remote-tracking ref#702
wesm merged 3 commits intomainfrom
fix/branch-review-bug

Conversation

@wesm
Copy link
Copy Markdown
Collaborator

@wesm wesm commented May 7, 2026

Summary

  • Fix roborev review --branch and the post-commit branch review hook pulling unrelated trunk commits into the review range when local <base> is stale relative to origin/<base> (e.g., after rebasing a feature branch onto origin/main without pulling local main).
  • GetBranchBase now translates a bare branch.<name>.base config value to its remote-tracking counterpart (the branch's @{upstream} when configured, else origin/<name>) when the local branch is just an ancestor of the remote-tracking ref.
  • Qualified refs (containing /) and divergent local branches pass through unchanged so explicit user intent is preserved.
  • Adds unit tests for GetBranchBase resolution and end-to-end tests for both the --branch CLI flag and the post-commit hook against the rebased-stale-local scenario.

GetBranchBase returned the literal branch.<name>.base config value, so a
bare name like "main" was used as a local-branch ref. When local main
lagged behind origin/main (e.g., after rebasing a feature branch onto
origin/main without pulling local main), merge-base(local-main, HEAD)
walked back through commits already merged into the remote trunk, and
the resulting range pulled in unrelated trunk commits.

GetBranchBase now translates a bare name to the remote-tracking ref
(local branch's @{upstream} when configured, else origin/<name>) when
local <name> exists and is an ancestor of the remote-tracking ref.
Qualified refs (containing '/') and divergent local branches are passed
through unchanged so explicit user intent is preserved.
@roborev-ci
Copy link
Copy Markdown

roborev-ci Bot commented May 7, 2026

roborev: Combined Review (f256cd8)

Summary verdict: Changes are mostly sound, but two medium-risk Git ref resolution edge cases remain.

Medium

  • internal/git/git.go:1378: Treating every configured base containing / as a qualified remote ref skips stale-base resolution for valid local branch names like release/1.2 or team/main. This leaves the stale-local-base bug unresolved for common slash-containing branch names.

    • Fix: Check whether the value actually resolves as refs/remotes/<value> or matches a configured remote prefix, while still allowing local refs/heads/<value> branch names with slashes to use stale-ancestor translation.
  • internal/git/git.go:1401: If the local base branch has a configured upstream but that remote-tracking ref is missing, preferredRemoteTracking falls back to origin/<name> when it exists. In fork workflows where local main tracks upstream/main, this can silently choose the fork’s origin/main instead of respecting that the intended upstream is unavailable.

    • Fix: When readUpstreamConfig returns a configured upstream, use it only if it resolves; otherwise return no preferred remote-tracking ref instead of falling back to origin/<name>.

Synthesized from 3 reviews (agents: codex, gemini | types: default, security)

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 7, 2026

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 94.28571% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/git/git.go 94.28% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

Two refinements to the stale-local-base translation in GetBranchBase,
addressing review feedback on PR #702:

1. Slash-containing local branch names. The previous logic treated any
   '/' in the config value as a qualified remote-tracking ref and
   skipped translation. Branch names like "release/1.2" or "team/main"
   are valid local branches, so the original stale-local-base bug
   resurfaced for them. isQualifiedRemoteRef now checks ref namespace
   directly: a value is treated as already-qualified only when
   refs/remotes/<value> resolves AND no shadowing refs/heads/<value>
   exists, matching git's standard ref lookup precedence.

2. Configured upstream that does not resolve. When local <base> is
   explicitly configured to track a remote-tracking ref but that ref
   has not been fetched, preferredRemoteTracking previously fell
   through to origin/<base>. In fork workflows where local main tracks
   upstream/main and origin is the user's fork, this silently switched
   the comparison to a different remote. The fork-fallback now only
   triggers when no upstream is configured at all; an explicit but
   unresolved upstream returns "" so the literal local branch is used
   instead.
@roborev-ci
Copy link
Copy Markdown

roborev-ci Bot commented May 7, 2026

roborev: Combined Review (7ff1e6b)

Review verdict: one Medium issue remains; no Critical or High findings reported.

Medium

  • internal/git/git.go:1387 - Explicit remote-qualified bases can resolve to the wrong remote. If branch.feature.base = upstream/main, refs/remotes/upstream/main is missing, and refs/remotes/origin/upstream/main exists, the code can fall through from isQualifiedRemoteRef into preferredRemoteTracking and incorrectly review against origin/upstream/main.

    Suggested fix: Treat values whose first path component is a configured remote as pass-through explicit refs, or only apply the origin/<name> fallback for slash-containing values when refs/heads/<name> exists locally. Add a regression test covering missing upstream/main with existing origin/upstream/main.


Synthesized from 3 reviews (agents: codex, gemini | types: default, security)

Reviewer caught a residual case in PR #702: branch.feature.base =
"upstream/main" with refs/remotes/upstream/main absent and a stray
refs/remotes/origin/upstream/main present collapses to "origin/upstream/
main" — silently switching the comparison to a different remote.

preferredRemoteTracking now applies the origin/<name> fallback for
slash-containing names only when refs/heads/<name> exists locally. A
remote-qualified value whose configured remote-tracking ref isn't
fetched is passed through literally so git surfaces a clear "ref does
not resolve" error instead of computing the merge-base against an
unrelated remote.
@roborev-ci
Copy link
Copy Markdown

roborev-ci Bot commented May 7, 2026

roborev: Combined Review (81ed958)

No Medium, High, or Critical issues found across the reviews.

All agents reported the change as clean.


Synthesized from 3 reviews (agents: codex, gemini | types: default, security)

@wesm wesm merged commit 0bbd6bb into main May 7, 2026
8 checks passed
@wesm wesm deleted the fix/branch-review-bug branch May 7, 2026 17:28
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.

2 participants