# How no-mistakes Handles Fork URL Routing for GitHub PRs with Parent Repositories

> Discover how no-mistakes handles fork URL routing for GitHub PRs, simplifying CLI commands to connect forks with parent repositories using the <forkOwner>:<branch> syntax.

- Repository: [Kun Chen/no-mistakes](https://github.com/kunchenguid/no-mistakes)
- Tags: how-to-guide
- Published: 2026-06-27

---

**no-mistakes stores an optional fork URL in the repository record and constructs GitHub CLI commands that route pull requests from the fork to the parent repository using the `<forkOwner>:<branch>` head reference syntax.**

no-mistakes is an open-source CI/CD pipeline tool that automates pull request creation across multiple source control providers. When working with forked repositories, the tool implements a dedicated fork URL routing mechanism that allows contributors to open PRs from their personal fork while correctly targeting the upstream parent repository.

## Storing Fork URLs in the Database Schema

The fork URL configuration begins with repository initialization. When you run `no-mistakes init --fork-url`, the tool persists the fork URL in the `repos` table under the `fork_url` column. This value is accessed throughout the pipeline via the `Repo` struct defined in [`internal/db/repo.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/db/repo.go).

```go
type Repo struct {
    ForkURL string   // fork_url column in database
}

```

According to the source in [`repo.go`](https://github.com/kunchenguid/no-mistakes/blob/main/repo.go#L14-L17), this field remains empty unless explicitly configured, making fork support fully optional for repository records.

## Detecting the Provider and Building the Host

When a pipeline run reaches the PR creation step, `PRStep.Execute` in [`internal/pipeline/steps/pr.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/pr.go) calls `scm.DetectProvider` to identify the source control provider from the upstream URL. The step then invokes `buildHost` (located in [`internal/pipeline/steps/host.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/host.go)) to construct a provider-specific host interface.

```go
provider := scm.DetectProvider(sctx.Repo.UpstreamURL)
host, skipReason := buildHost(sctx, provider)   // L48-L50 in host.go

```

The `buildHost` function examines `sctx.Repo.ForkURL` to determine if fork routing is required. For GitHub repositories, it extracts repository slugs from both the upstream URL and the fork URL, passing these to the GitHub-specific constructor.

## GitHub-Specific Fork Routing Implementation

For GitHub providers, the `buildHost` function handles fork URLs by extracting the owner/name slug from both the parent and fork repositories. Located at L24-L36 in [`host.go`](https://github.com/kunchenguid/no-mistakes/blob/main/host.go), this logic prepares the arguments for `github.NewWithFork`:

```go
repo := github.RepoSlug(sctx.Repo.UpstreamURL)
if sctx.Repo.ForkURL != "" {
    forkRepo = github.RepoSlug(sctx.Repo.ForkURL)
}
return github.NewWithFork(cmdFactory,
    func() bool { return stepCLIAvailable(sctx, provider) },
    repo, forkRepo), ""

```

The `github.NewWithFork` constructor, found in [`internal/scm/github/github.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/scm/github/github.go#L40-L44), stores the fork owner separately within the `Host` struct:

```go
h.forkOwner = repoOwner(forkRepo)

```

This separation allows the host to distinguish between the target repository (parent) and the source repository (fork) throughout the PR creation process.

## Creating Pull Requests with Fork Head References

When `Host.CreatePR` executes, it uses the `headRef` method to determine the appropriate `--head` argument for the GitHub CLI. This method checks for the presence of a fork owner and formats the reference accordingly.

In [`internal/scm/github/github.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/scm/github/github.go#L82-L86), the PR creation command is constructed as follows:

```go
args := append([]string{"pr", "create",
    "--head", h.headRef(branch),
    "--base", base},
    h.repoArgs()...)

```

The `headRef` method implements the conditional logic that routes the PR to the correct source:

```go
func (h *Host) headRef(branch string) string {
    if h.forkOwner == "" {
        return branch               // no fork: use branch directly
    }
    return h.forkOwner + ":" + branch // fork: use owner:branch syntax
}

```

This produces the `forkOwner:branch` syntax required by GitHub to identify pull request sources from forked repositories, ensuring the PR originates from the contributor's fork while targeting the parent repository's default branch.

## Limitations with GitLab and Bitbucket

The fork URL routing implementation is currently specific to GitHub. When `buildHost` encounters a fork URL configured for GitLab or Bitbucket providers, it returns a skip reason indicating the feature is not yet implemented.

In [`host.go`](https://github.com/kunchenguid/no-mistakes/blob/main/host.go#L38-L42) and L46-L50), the code explicitly handles these cases:

```go
if sctx.Repo.ForkURL != "" {
    return nil, "fork PR routing for GitLab is not implemented"
}

```

This ensures the pipeline fails gracefully with a clear explanation rather than attempting unsupported fork operations on these providers.

## Summary

- **Fork URL Storage**: The `fork_url` column in the `repos` table stores the optional fork URL, accessible via `sctx.Repo.ForkURL` throughout the pipeline.
- **Host Construction**: `buildHost` in [`host.go`](https://github.com/kunchenguid/no-mistakes/blob/main/host.go) detects fork configurations and delegates to `github.NewWithFork` for GitHub repositories.
- **Owner Extraction**: The GitHub host stores the fork owner separately from the repository slug, enabling precise PR source routing.
- **Head Reference Format**: The `headRef` method generates `<forkOwner>:<branch>` syntax for forks, which the GitHub CLI translates to the correct source repository.
- **Provider Limitations**: Fork URL routing is only implemented for GitHub; GitLab and Bitbucket repositories with fork URLs are skipped with explanatory error messages.

## Frequently Asked Questions

### How do I configure a fork URL when initializing a repository?

Use the `--fork-url` flag with the `no-mistakes init` command. For example: `no-mistakes init --fork-url https://github.com/your-username/no-mistakes.git`. This persists the URL in the database and enables fork routing for subsequent PR operations.

### Why does no-mistakes skip PR creation when using a fork URL with GitLab?

As implemented in [`internal/pipeline/steps/host.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/host.go), the `buildHost` function returns a skip reason for GitLab and Bitbucket repositories when a fork URL is present. The code explicitly states that "fork PR routing for GitLab is not implemented," indicating this functionality is currently GitHub-specific.

### What is the difference between the head reference for forked and non-forked PRs?

For standard PRs without forks, the head reference is simply the branch name (e.g., `feature-branch`). For forked repositories, the `headRef` method in [`github.go`](https://github.com/kunchenguid/no-mistakes/blob/main/github.go) prefixes the branch with the fork owner (e.g., `fork-owner:feature-branch`). This syntax tells GitHub to look for the branch in the contributor's fork rather than the parent repository.

### Which source files handle the fork routing logic?

The primary files involved are [`internal/db/repo.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/db/repo.go) (schema definition), [`internal/pipeline/steps/host.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/host.go) (provider detection and host building), and [`internal/scm/github/github.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/scm/github/github.go) (GitHub-specific PR creation with fork owner handling). The PR step execution is coordinated from [`internal/pipeline/steps/pr.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/pr.go).