How no-mistakes Handles Fork Routing for GitHub PRs: A Technical Deep Dive

no-mistakes routes branch pushes to a contributor's fork while always targeting the upstream repository for pull request creation, using a dual-URL configuration stored in the repos table.

The open-source tool no-mistakes (available at kunchenguid/no-mistakes) implements a sophisticated fork routing system that separates where code is pushed from where pull requests are opened. This architecture allows contributors to work on forks without write access to the parent repository while ensuring all GitHub PRs are created against the canonical upstream project.

Dual-URL Configuration for Fork Routing

The system maintains two distinct remote URLs for every repository entry in its database. The upstream_url field stores the canonical GitHub repository (the parent), while the optional fork_url field contains the contributor's personal fork address.

These values are persisted in the repos table and drive all subsequent routing decisions. When fork_url is populated, the tool assumes the contributor intends to push changes to their own fork rather than the upstream repository.

The PushURL Method: Routing Commits to the Correct Remote

The core routing logic resides in internal/db/repo.go within the PushURL() method. This function determines which remote receives branch updates by checking the presence of a configured fork:

// PushURL returns the remote URL that should receive branch updates.
func (r *Repo) PushURL() string {
    if r == nil {
        return ""
    }
    if strings.TrimSpace(r.ForkURL) != "" {
        return r.ForkURL        // fork takes precedence
    }
    return r.UpstreamURL          // otherwise push to the parent
}

When the push step executes in internal/pipeline/steps/push.go, it invokes sctx.Repo.PushURL() to determine the destination for git push operations. This ensures that contributors without upstream write permissions can still publish branches to their own forks.

GitHub PR Creation: Always Targeting Upstream

For GitHub PR creation, no-mistakes employs a different routing strategy than it uses for pushes. The workflow enforces that the pull request target must always be the parent repository, regardless of whether a fork is configured.

The implementation in internal/pipeline/steps/host.go constructs the gh pr create command with the following behavior:

  • The --repo flag always points to the upstream repository (derived from upstream_url)
  • When fork_url is present, the command adds --head <fork_owner>:<branch> to specify the fork as the PR head
  • The fork_url itself is never passed directly to the gh command; only the fork owner name is extracted from the URL

This split-routing approach ensures that while branch updates land on the contributor's fork, the pull request itself is opened against the trusted upstream repository.

Security and Workflow Benefits

This dual-routing architecture provides critical security and convenience advantages:

  • Permission isolation: Contributors can open PRs without requiring write access to the upstream default branch
  • Trusted targets: Maintainers control the target branch configuration on the upstream repository, preventing accidental PRs against incorrect branches
  • Clean history: Branch updates occur on the fork, keeping the upstream repository's branch list uncluttered

Summary

  • no-mistakes stores two URLs per repository: upstream_url for the parent repo and fork_url for contributor forks
  • The PushURL() method in internal/db/repo.go prioritizes the fork URL when determining where to push branches
  • Push operations in internal/pipeline/steps/push.go use the fork when available, enabling contributions without upstream write access
  • PR creation always targets the upstream repository via --repo, using --head <fork_owner>:<branch> when a fork is configured
  • The fork_url is never used directly for PR creation; only the owner name is extracted in internal/pipeline/steps/host.go

Frequently Asked Questions

What is fork routing in no-mistakes?

Fork routing is the system's mechanism for directing Git operations to different remotes based on context. It pushes code to a contributor's fork (when configured) while ensuring GitHub pull requests are always created against the upstream parent repository.

How does no-mistakes decide whether to push to a fork or upstream?

The decision occurs in the PushURL() method inside internal/db/repo.go. If the ForkURL field contains a non-empty string, that URL is returned and used for push operations. Otherwise, the method falls back to UpstreamURL.

Why doesn't no-mistakes use the fork URL directly when creating PRs?

The tool intentionally avoids passing the fork URL to gh pr create because GitHub CLI requires the --repo flag to specify the target repository for the PR (which must be the upstream), while the fork is referenced only as the head source via --head <owner>:<branch>. This maintains the security model where the upstream repository controls the merge target.

Which database fields control fork routing behavior?

The routing behavior is controlled by two columns in the repos table: upstream_url (the canonical parent repository) and fork_url (the optional contributor fork). The presence of a value in fork_url triggers fork-specific routing for pushes and modifies the PR creation command to include the fork owner prefix.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →