Skip to content

Feature: Fork workflow support — separate upstream and push remotes #1800

@schultzp2020

Description

@schultzp2020

Feature Summary

Support a fork-based development workflow where two remotes serve different roles: an upstream remote (read-only, where PRs and issues live) and an origin remote (the user's fork, where branches are pushed). Currently emdash only supports a single configured remote that is used for all operations — fetching, pushing, PR creation, and issue tracking.

Problem or Use Case

Contributors who fork a repository need to:

  • Fetch and sync worktrees from upstream (the canonical repo)
  • Push branches to origin (their fork)
  • Create PRs targeting upstream as the base, with the head branch on origin
  • Browse issues from upstream

With the current single remote setting, you have to choose one remote for everything. Setting it to upstream breaks pushing (no write access). Setting it to origin means default branch detection, issue fetching, and PR base targeting all point at the fork instead of the canonical repo.

This is the standard workflow for open-source contributors and teams where developers don't have write access to the main repository.

Proposed Solution

Add a second remote role to project settings — something like a "push remote" alongside the existing "sync remote." The existing remote setting would continue to control fetching, default branch resolution, issue tracking, and PR base targeting (the upstream). The new setting would control where branches are pushed and published.

UX:

  • A new "Push remote" dropdown in project settings, shown below the existing "Remote" selector
  • Defaults to the same value as "Remote" when unset (preserving current behavior)
  • When set to a different remote, push operations target the push remote while fetch/sync/PR-base/issues use the primary remote

Operations that would use the push remote:

  • publishBranch() / push()
  • Setting upstream tracking on new branches
  • The push step before PR creation

Operations that stay on the sync remote (current remote):

  • Worktree fetch/sync
  • Default branch resolution
  • Issue queries
  • PR base branch candidates
  • GitHub repo URL detection (for PR/issue API calls)

PR creation requires special handling. Currently octokit.rest.pulls.create() is called with owner/repo derived from the configured remote and head as a bare branch name. For cross-fork PRs, the GitHub API requires:

  • owner/repo to be the upstream repository
  • head to be prefixed with the fork owner (e.g. myuser:feature-branch)

This means the PR creation backend needs to accept and pass the fork owner prefix, and the create-PR modal needs to be aware of both remotes to construct the correct API call.

Alternatives Considered

The current workaround is to manually push to origin via the terminal and create PRs through the GitHub UI, bypassing emdash's task workflow and PR creation features entirely.

Auto-detecting the fork relationship via the GitHub API (GET /repos/{owner}/{repo} returns parent/source for forks) could complement the explicit setting but shouldn't replace it — an explicit setting is more predictable and works for non-GitHub remotes or unconventional setups.

Additional Context

Emdash already has fork awareness for the maintainer side — fetchPrForReview() detects incoming fork PRs and temporarily adds the contributor's fork as a remote. This feature request is the contributor side of the same coin.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions