Skip to content

fix(server): an upstream shadowed by a local origin/<branch> branch keeps its real remote - #29180

Merged
maria-rcks merged 1 commit into
pingdotgg:mainfrom
saphid:fix/ambiguous-upstream-ref
Nov 3, 2026
Merged

maria-rcks merged 1 commit into
pingdotgg:mainfrom
saphid:fix/ambiguous-upstream-ref

Conversation

@saphid

@saphid saphid commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Problem

A branch feature tracks origin/feature, and the repository also has a local branch literally named origin/feature. That happens easily after git checkout -b origin/feature or git branch origin/x. In that case git rev-parse --abbrev-ref @{upstream} prints remotes/origin/feature, and T3 reads the upstream remote as remotes:

  • The background status refresh fetches a remote named remotes. It fails every time and backs off, so behind counts never refresh.
  • Push treats the upstream as a "differently named" base. It writes branch.feature.t3-merge-base=origin/feature and t3-merge-base-ref=refs/remotes/remotes/origin/feature (a ref that does not exist) to git config. A later PR then resolves that base to the local origin/feature branch and targets the wrong base.

Change

readCurrentUpstreamRef now reads the full upstream ref (rev-parse --symbolic-full-name @{upstream}) and strips refs/remotes/ itself. It also strips refs/heads/, so a local (remote = .) upstream gives the same short value as before. This follows #24258 (branchNameFromHeadRef, the same problem with tag shadowing) and the sibling resolveTrackedRemoteBaseRef, which already reads full refs so a similarly named local branch cannot shadow the remote one.

The ahead/behind count in statusDetailsRemote now compares against HEAD...@{upstream} instead of the shortened name. Otherwise origin/feature would resolve to the shadowing local branch.

Scope and approval

Very small, focused fix for an obvious bug, so no prior issue: one function reads the upstream with the same shortened-ref ambiguity #24258 already fixed for the branch name, plus the one comparison that consumed that name. Overlap search: #24258 (merged) fixed only the HEAD branch read. #19802 (merged) avoided remote enumeration in status reads. Open #24047 uses --abbrev-ref @{upstream} only in tests and does not touch readCurrentUpstreamRef. No open PR changes this read.

Verification

  • Extended the existing "repository status" case that covers tag shadowing in GitVcsDriverCore.test.ts. It now tracks a bare remote, adds an unpushed commit, creates a local origin/release branch, and asserts upstreamRef === "origin/release" and aheadCount === 1.
  • Red on main: AssertionError: expected 'remotes/origin/release' to equal 'origin/release'. With only the upstream read fixed, the count assertion failed with expected +0 to equal 1.
  • Green: vp test run src/vcs/GitVcsDriverCore.test.ts: 223 passed, 1 failed. The failure is "keeps generated worktree folders short without changing long branch names", a macOS /var vs /private/var path mismatch that also fails on clean main.
  • GitManager, VcsStatusBroadcaster, and SourceControlRepositoryService tests: 163/163 passed.
  • vp run check:changed: format, lint, knip, graphql, and typecheck pass. Tests fail only on the same macOS case.
  • Before the fix, I ran a manual repro against a real bare remote: status showed remotes/origin/feature, the background fetch failed, and push wrote t3-merge-base-ref = refs/remotes/remotes/origin/feature. I did not rerun that end-to-end script against this branch. The test covers the status path, and push consumes the same parsed remote.

Reviewed with sol-loop: 2 rounds with GPT-6.1 Sol on high. Sol verdict: approved. Round 1 caught the ahead/behind comparison, which is fixed here.

Created with Claude Opus 5.5 in Claude Code (T3 Code).

🤖 Generated with Claude Code

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XS 0-9 changed lines (additions + deletions). vouch:trusted Author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants