Skip to content

[Bug]: Fork checkouts resolve "the primary remote" four different ways, so features disagree on the repository #17314

Open

Description

@tris203

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

  1. Clone a fork. Set origin to <you>/<repo> and add upstream for <org>/<repo>.
  2. Make local main track upstream/main. Optionally run gh repo set-default.
  3. Add the checkout as a T3 project and use it normally: start worktrees, open PRs, enable Automatically pull and Delete merged worktrees.

Expected behavior

Every feature agrees on which remote is the source repository (where main comes from and PRs land) and which is the fork (where branches are pushed).

Actual behavior

Each feature answers that question with its own rule, so in one checkout they point at different repositories:

Feature Rule at 580948708b Picks in a fork checkout Report
Project identity pickPrimaryRemote: upstream, then origin source repository #15023
gh base repository selectGitHubBaseRepository: the gh-resolved mark, then gh's own name ranking whatever gh repo set-default chose #15023, #7382
Merged-worktree cleanup, GitManager, Bitbucket resolvePrimaryRemoteName: origin if it exists, else the first remote fork #14843
Start from origin the literal "origin" in ThreadLaunchService and WorktreeMcpService fork #17312
Automatically pull git pull --ff-only, so the branch's configured tracking remote source repository (works)

The visible results are the four linked reports: fork PRs that do not link to the thread, PR creation that fails, merged worktrees that are never cleaned up, and new worktrees that start from a stale base. Each one is a caller asking for "the primary remote" and getting an answer that suits a different job.

A fork checkout has two remotes with different jobs, so one "primary remote" cannot be right for all callers:

  • a base remote: where the default branch comes from and where PRs are opened;
  • a push remote: where the user's branches go.

This report is the common cause, not a fifth symptom. I found it by reading main at 580948708b; the individual symptoms carry their own runtime evidence in the linked issues.

Suggested direction

One place that resolves both roles for a checkout, used by all of the callers above. The signals already in use would feed it: the gh-resolved mark, the default branch's tracking remote, remote.pushDefault / branch.<name>.pushRemote, then the remote names as a fallback. A checkout with a single remote resolves both roles to it, so nothing changes outside fork setups.

I am not asking for this to be implemented as described. The decision I would like is whether the four reports should keep being fixed one caller at a time, or share one rule.

Two things to weigh:

Impact

Major degradation or frequent failure

Version or commit

main at 580948708b66f2a971199670f76cb6b43119e9a4 (2026-10-08)

Environment

Linux x86_64, Git 2.43.0. Fork checkout with origin = fork, upstream = source repository, branch.main.remote=upstream, remote.upstream.gh-resolved=base.

Workaround

Keep the fork's default branch synced with the source repository (gh repo sync). That hides the worktree-base and cleanup symptoms. It does not help #15023 or #7382.

Prepared with Claude Opus 5.5 through the Claude Code harness in T3 Code.

Activity

  1. benthecarman commented on Oct 8, 2026

    @benthecarman
    Contributor

    +1 for one shared rule. I hit the "Start from origin" symptom (#17312) in a standard fork checkout (origin = fork, upstream = source). Project identity already treats upstream as the source repository, and worktree creation treats origin as the source, so they disagree. A single base/push resolver would remove that mismatch. Any fallback that checks the remote names should treat upstream as the base remote, so that setups that don't track upstream still work.

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

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