Skip to content

PR status does not show up for PRs opened from a fork to the upstream repo #255

@zhuwenxing

Description

@zhuwenxing

Summary

When working in a forked repository and opening pull requests against the
upstream repo, Supacode does not display any PR status for the related
worktrees, and PR actions from the command palette (Merge / Close / Mark
ready for review) silently act on the wrong repository.

This is different from #37 / #229, which handled filtering fork PRs inside
the GraphQL response. The issue here is that Supacode picks the wrong
repository to query in the first place.

Symptom

In a local clone where the user pushes branches to their fork and the PRs
are opened against the upstream repo:

  • Worktree rows show no PR badge and no CI ring, even when a PR exists.
  • "Merge PR", "Close PR", and "Mark ready for review" from the command
    palette either no-op or fail — they run gh pr … against the fork,
    where the PR does not exist.

Root cause

GitClient.remoteInfo(for:) at supacode/Clients/Git/GitClient.swift:433-468
prefers the origin remote and falls back to other remotes only when
origin is missing or non-GitHub. In a fork workflow origin points at
the fork, so the resolved (host, owner, repo) is the fork's.

That tuple flows into GithubCLIClient.batchPullRequests
(supacode/Clients/Github/GithubCLIClient.swift:232-256), which queries
the fork's repository via GraphQL and returns [:] since no PRs live
there. RepositoriesFeature.refreshRepositoryPullRequests
(supacode/Features/Repositories/Reducer/RepositoriesFeature.swift:2566-2602)
then sets pullRequest = nil for every worktree.

The mutation fetchers (mergePullRequest, closePullRequest,
markPullRequestReady at GithubCLIClient.swift:259-311) similarly
invoke gh inside repoRoot without --repo, so they act on the fork.

Relying on remote names to recover is not a viable workaround: remote
naming is a convention, not a rule. Users routinely have remotes named
`upstream`, `source`, the original author's username, the organization
name, etc.

The information Supacode needs is already provided by `gh`

`gh` resolves the "default" repository for a local clone (upstream of a
fork, PR target, etc.) using its own heuristics and exposes the result
through `gh repo view`. In a clone with multiple remotes and no explicit
`gh repo set-default`, `gh repo view --json owner,name` returns the
upstream owner and name, and `gh pr list --head ` correctly lists
PRs from the upstream repository. The same resolution is applied whenever
`gh pr merge/close/ready` run in the repo without `--repo`.

Supacode is effectively bypassing this resolution by computing its own
`(host, owner, repo)` from the remote list and passing it explicitly.

Suggested direction

  1. Replace the hand-rolled `origin`-first logic in `GitClient.remoteInfo`
    with a call to `gh repo view --json owner,name` executed in `repoRoot`,
    falling back to the current remote parsing only if `gh` is unavailable.
  2. Pass the resolved `owner/name` to `batchPullRequests` so the GraphQL
    query hits the right repository. The existing fork-fallback logic in
    `pullRequestsByBranch` continues to apply.
  3. Either drop the explicit repo arguments from the PR mutation fetchers
    and let `gh` resolve `repoRoot`, or pass `--repo /` with
    the value from step 1.
  4. Keep CI-related calls (`gh run list`, rerun failed jobs, view run
    logs) on `repoRoot`. Workflow runs live on whichever remote received
    the push — in fork workflows that is the fork — and the current
    `gh run list` without `--repo` already targets it correctly.

An optional override in Repository Settings (similar to "Merge strategy")
would cover edge cases where `gh`'s resolution doesn't match the user's
intent, but the default behavior should work out of the box.

Reproduction

  1. Fork any upstream repository you don't own and clone the fork.
  2. Add the upstream as an additional remote.
  3. Open the clone in Supacode, create a worktree, push a branch, open a
    PR against the upstream on GitHub.
  4. Observe: the worktree shows no PR; command palette actions on the PR
    do not affect the upstream PR.

Environment

  • Supacode `main` at `7981cf3`
  • macOS 26.x
  • `gh` 2.x

Affected files

  • `supacode/Clients/Git/GitClient.swift`
  • `supacode/Clients/Github/GithubCLIClient.swift`
  • `supacode/Features/Repositories/Reducer/RepositoriesFeature.swift`

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions