Repository navigation
fix(github): stop feature branches from borrowing unrelated PRs - #27332
Conversation
…acks A branch made with `git switch -c feature/x origin/develop` tracks the default branch. When its own PR lookup missed, the tracked-upstream fallback attached the newest PR whose head is `develop` (an unrelated develop to release PR) and cached its number, so the wrong link survived restarts. Drop a match headed by the tracked upstream when that upstream is the default branch of a repo PRs target. The check runs only after such a match, so normal polling adds no git calls, and it also heals numbers cached before the fix. Fixes #26948
… branch A fork's upstream remote can default to a different branch than origin. Read refs/remotes/<remote>/HEAD for the tracked remote and fall back to origin's default only when git never recorded it. Reuses the default-branch resolver's host routing and cache.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Priority: ➖ Normal Severity of issue fixed: Medium Merge Risk: 🔵 Low · up to When GitHub cannot provide enough PR metadata, an unrelated cached PR may remain visible. The risk is bounded and can be accepted with awareness or addressed before merging. Pre-merge checks |
|
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
872d82e9-7a0f-4c0c-9f8c-4b68a1df38ad
📒 Files selected for processing (14)
src/main/github/client-merge-queue-auto-merge.test.tssrc/main/github/client-pr-branch-discovery.test.tssrc/main/github/client-pr-fallback-number.test.tssrc/main/github/client-pr-linked-lookup.test.tssrc/main/github/client-tracked-upstream-default-branch.test.tssrc/main/github/client-tracked-upstream-fork-owner.test.tssrc/main/github/client-tracked-upstream-snapshot.test.tssrc/main/github/client/lookup/branch-lookup-resolution.tssrc/main/github/client/lookup/implicit-default-branch-pr.tssrc/main/github/client/lookup/pull-request-lookup-data.tssrc/main/source-control/repo-default-branch.tssrc/main/source-control/repo-remote-head-branch.test.tssrc/shared/git-default-base-ref.tssrc/shared/git-resolution-binary-compatibility.test-cases.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 0 remain after this review.
Apply the default-branch policy while probing each repository, so an integration PR cannot preempt a valid result or suppress the same number in another repository. Check branch heads by repository and server. Invalidate remote defaults when their review scope or SSH provider changes. Report rejected PR URLs through an optional refresh-result field, so merged integration PRs clear from both caches even at the current worktree head. Share the manual and coordinator cache update implementation. Co-authored-by: petersindex <287557875+petersindex@users.noreply.github.com>
Use the existing REST PR mapping to read the head repository's default branch when no tracked remote or origin can identify it. Require matching repository and head metadata, and preserve the PR if the lookup fails. This clears both closed and merged integration PRs cached by a fork checkout after its upstream tracking is removed. Co-authored-by: petersindex <287557875+petersindex@users.noreply.github.com>
ELI5
A new feature branch should show its own PR, not a release PR belonging to the branch it started from. Old incorrect links should also clear after a refresh.
What Changed
Before, a feature branch tracking
origin/developcould show an unrelated develop-to-release PR, including its checks and actions. The incorrect link could survive restarts, and a merged PR could remain cached just because its commit matched the new branch.The shared lookup now checks each PR's actual head repository and GitHub server, then compares the head branch with that repository's own default. It rejects inferred integration PRs while preserving fork PRs, renamed local branches, explicit links, and detached checkouts. Rejections include the repository and server, so identical PR numbers in different repositories cannot suppress each other. Candidate probing continues after a rejected result.
An optional refresh-result field identifies rejected PR URLs so both renderer caches clear that exact link, even at its merged commit. Manual and background refreshes now share one cache-update implementation. Remote-default caches also refresh after repository invalidation or SSH provider replacement.
Why
Removing upstream discovery would break renamed branches and contributor checkouts; matching only a branch name would hide legitimate fork PRs. Full repository identity distinguishes these cases. Filtering each candidate lets cached-number recovery continue to a valid PR instead of stopping at an unrelated one. Explicit rejection lets the renderer heal an old incorrect link while retaining its existing preservation of legitimate merged PRs.
Default resolution reuses PR metadata and the existing host-owned Git runner, bounded cache, and concurrent-probe handling. An unknown upstream default does not borrow another repository's origin default. When removed tracking leaves a cached PR without a matching remote, one targeted REST lookup reads that PR head repository's own default; unavailable or inconsistent metadata preserves the existing PR.
Linked Issue
Fixes #26948
Visual Proof
N/A — this changes review-data selection and cache invalidation; no rendered components or interaction controls changed. Automated regressions cover manual and background refreshes, both caches, and persisted removal of the incorrect link.
Testing
On macOS, manually verified the reported Git branch/upstream setup in a temporary repository. All tests and builds used background-launch mode.
TMPDIR=/private/tmpfor the existing registration test's macOS temporary-directory symlink assumption.The adversarial review reproduced and fixed eight edge cases: rejection collisions between repository-local PR numbers; recovery stopping at the first invalid repository; stale defaults after SSH provider replacement or repository invalidation; accepting a head from a different repository or GitHub server; preserving a rejected merged integration PR at the current worktree commit; and retaining an integration PR from a different repository after upstream tracking was removed. Regression fixtures route responses by server, repository, and PR number.
Additional coverage protects fork heads with different repository names, different remote defaults, cached feature-PR recovery, removed upstream tracking, missing metadata/remote HEADs, explicit links, detached checkouts, concurrent probes, WSL/SSH separation, and disconnected SSH without local fallback. The real-Git contract covers remote-specific HEAD resolution in the existing Git 2.25.5 / 2.38.1 / 2.49.1 CI matrix. Windows and live SSH were not manually exercised.
Review
Reviewed repository/server identity, rejection and persistence, concurrent refresh ownership, remote cache invalidation, failure behavior, and platform routing. No blocking findings remain in this review. Provider-specific PR matching stays within the GitHub client; the existing source-control resolver owns native, WSL, and SSH Git execution.
The optional no-PR response field preserves mixed-version operation: older clients ignore it and newer clients still accept responses from older hosts. No RPC parameters or stream opcodes change. Head-repository metadata is requested in existing GitHub calls, with no added repository-wide scans. The existing linked-merged-PR divergence check was extracted without changing its behavior.
Agent skill upstream boundary
Notes
Credit to @petersindex for the diagnosis, initial fix, and remote-specific default resolution in #27180. Both original commits retain their authorship, and both follow-up fixes explicitly include
Co-authored-by: petersindex <287557875+petersindex@users.noreply.github.com>.Checklist
N/Awith reason