Collaborating on GitHub
Topic 36

The Forking Workflow

Collaboration

Forking creates your own server-side copy of a repository you cannot push to, so you can make changes and propose them back through a pull request. It is the standard model for open source and for any contribution that crosses an organization boundary, because it requires no write trust: you work entirely in your copy until a maintainer chooses to merge.

The whole workflow comes down to keeping two remotes straight — the original repo and your copy of it — and not letting your copy drift so far behind that the eventual pull request is a wall of conflicts. Get those two habits right and forking is no harder than branching.

Fork, Origin, Upstream

When you fork, your copy becomes origin — the remote you clone from and push to. The original repository is conventionally added as a second remote named upstream, which you fetch from but never push to. Keeping these two names straight is the entire mental model: you pull new work from upstream and publish your contributions to origin.

A fresh clone of your fork has only origin configured. You add the original with git remote add upstream <url>, and from then on git remote -v shows both, making it obvious which is yours and which is the source of truth.

Syncing a Fork

Your fork is a snapshot taken at the moment you created it; it does not update itself. The instant the original repository gains a commit, your fork is behind. You catch up with git fetch upstream followed by a merge or rebase onto upstream/main, or by clicking the "Sync fork" button GitHub shows on the fork's home page.

Syncing before you start each piece of work is what keeps a pull request small and reviewable. A fork that has not been synced in weeks produces a diff against a base the maintainer no longer recognizes.

Contributing via Pull Request

You never work on your fork's default branch. You create a feature branch in your fork, push it to origin, and open a pull request whose base is the upstream repository's branch and whose head is your fork's branch. GitHub recognizes the fork relationship and offers the cross-repository PR automatically.

Branching per contribution lets you have several pull requests open at once, each isolated, and lets you keep working while one of them waits for review.

Maintainer-Side Controls

When you open the pull request, the "Allow edits by maintainers" checkbox lets a maintainer push small fixes directly to your branch — a one-line typo or a rebase — instead of asking you to do it across a timezone gap. Maintainers can also fetch your branch locally to test or amend it before merging.

Fork vs Branch Decision

The choice is governed by access. If you have push access to the repository — you are on the team — you branch directly and skip the upstream sync entirely; branch protection applies to your branch as-is. If you do not have push access — open source, an external contributor — you fork, because it gives isolation without anyone having to grant you write permission first.

Forking Workflow vs Shared-Repository Workflow

Forking workflow — fork when you lack push access, as in open source or cross-org work. You get isolation by default and need no write trust, at the cost of maintaining an upstream remote and syncing your fork as the original moves.

Shared-repository (branch) workflow — branch directly when you are on the team with push access. It is simpler: no second remote, no fork syncing, and branch protection applies to your branch immediately. Choose it whenever you already have write permission.

Common Mistakes
  • Committing to your fork's default branch and opening the PR from it — every later upstream sync then conflicts and you cannot run two pull requests at once.
  • Letting a fork sit untouched for weeks, then opening a PR from a months-old base — the maintainer gets a conflict-heavy diff and bounces it back to you to rebase.
  • Forgetting to add an upstream remote, so you keep fetching from your own stale fork and never see new commits on the original.
  • Leaving "Allow edits by maintainers" unchecked, so a maintainer who could fix a one-line nit instead has to ask you to do it across timezones.
  • Force-pushing a rebase to your PR branch mid-review without warning — reviewers lose the comment anchors tied to the old commits.
Best Practices
  • Add the original repo as upstream and run git fetch upstream && git rebase upstream/main before starting each piece of work.
  • Always branch off an up-to-date base in your fork, and never commit to the fork's default branch.
  • Enable "Allow edits by maintainers" when opening a PR so a maintainer can push small fixes directly.
  • Open the pull request against the correct upstream base branch, not your own fork's branch.
  • Delete merged feature branches in your fork and re-sync from upstream before the next contribution.
Comparable toolsGitLab forks with the same upstream modelBitbucket forks and cross-repo PRsGitea forks and pull requestsAzure DevOps supports forks; team flow leans on branches

Knowledge Check

You have push access to a repository on your team. Fork or branch?

  • Branch directly — with push access you skip the fork, avoid an upstream remote, and branch protection covers it
  • Fork — every contribution should go through a personal copy regardless of your access level
  • Fork, because feature branches on a shared repository cannot be covered by branch protection or rulesets at all
  • Neither; commit your changes straight to the default branch and skip the PR

Why does a pull request from a months-old fork often get bounced back?

  • The fork's base has drifted far behind upstream, so the diff is full of conflicts the maintainer asks you to rebase
  • GitHub automatically blocks pull requests from any fork created more than 30 days ago
  • After enough time passes an old fork quietly loses its connection to the original repository and can no longer target it for a PR
  • A fork can only ever produce one pull request before it must be recreated

What is the role of the upstream remote?

  • It points at the original repository so you can fetch new work from it, while origin stays the fork you push to
  • It is the branch you push your changes onto before opening a pull request
  • It is GitHub's built-in name for your fork's own default branch
  • It is a backup remote that mirrors origin automatically on every push so that your fork always keeps a second copy

What does "Allow edits by maintainers" enable on your pull request?

  • A maintainer can push small fixes directly to your PR branch instead of asking you to make them
  • It grants you full write access to the upstream repository for the entire life of the pull request, letting you push to any of its branches
  • It auto-merges the pull request into the base branch as soon as the required checks pass
  • It lets maintainers delete your fork automatically from your account once the PR is merged and closed

You got correct