Forks, pull requests and review workflows

Fork versus branch models, syncing with upstream, protected branches and required checks, review etiquette, and rewriting a branch that is under review.

Fork or branch

# fork model: you have no write access to the upstream repository
git clone [email protected]:you/project.git
cd project
git remote add upstream [email protected]:org/project.git
git fetch upstream

git switch -c fix/timeout-handling upstream/main
# ... make the change ...
git push -u origin fix/timeout-handling
# then open a pull request from you:fix/timeout-handling into org:main

# branch model: contributors already have write access
git switch -c fix/timeout-handling origin/main
git push -u origin fix/timeout-handling
Fork modelBranch model
Write accessNot required on the base repositoryRequired
CI on a pull requestRuns on the fork; repository secrets are withheld by defaultRuns with the repository's secrets
SyncingAdd upstream and fetch itFetch origin as usual
Typical useOpen source, external contributorsTeams and internal repositories

Keeping a pull request reviewable

# keep your fork's main current
git fetch upstream
git switch main
git merge --ff-only upstream/main
git push origin main

# keep the feature branch current by rebasing it, not by merging main into it
git switch fix/timeout-handling
git rebase upstream/main
git push --force-with-lease

# what has changed since the reviewer last looked?
git log --oneline @{u}..HEAD
git diff origin/main...HEAD
  • Push to your own fork or your own branch; never push onto someone else's open pull request branch.
  • A pull request is a conversation about a diff. Under roughly 400 changed lines gets real review; several thousand lines gets an approval and a hope.
  • Protected base branches plus required checks enforce the rules. Reviewer discipline alone does not survive a deadline.
  • Explain the why in the description, list what you tested, and flag anything you are unsure about — reviewers find fewer bugs when they know where to look.
  • Review the code, not the author. Ask questions rather than issuing verdicts, and say which comments are blocking and which are preferences.
⚠️
Rewriting a branch under review invalidates every reviewer's local checkout. An announced force-push is fine; a silent one wastes an hour of someone else's day. Say what changed, and use --force-with-lease so you cannot overwrite a teammate's commits by accident.

Stacking pull requests

# a stack: three dependent pull requests
git switch -c part-1/schema main
# ... PR #101 opens against main ...
git switch -c part-2/api part-1/schema
# ... PR #102 opens against part-1/schema ...
git switch -c part-3/ui part-2/api
# ... PR #103 opens against part-2/api ...

# after part-1 is rebased, move the branch above it onto the new base
git rebase --onto part-1/schema old-part-1 part-2/api
  • Target each pull request at the branch below it, then retarget to main as the ones underneath merge.
  • Keep most stacks three or four deep. Beyond that, one branch with well-separated commits is easier for everyone to follow.
  • A squash merge creates a new commit, so any branch stacked on top must be rebased onto the updated main afterwards.
  • When a stack gets confusing, the fallback is one branch and a commit order that tells the story — reviewers can read commits one at a time.

FAQ

How do I review someone else's fork locally?
Add their fork as a remote (git remote add contributor [email protected]:them/project.git), fetch it, then check out their branch and run it. Remove the remote afterwards so stale copies do not accumulate.
Should we squash every pull request?
Squashing gives a linear main branch and one commit per feature, at the cost of the intermediate history. It suits small teams merging quickly; teams that later bisect regressions sometimes prefer the real commits. Pick one policy and apply it consistently.

Tags, releases and semantic versioning Clean history: interactive rebase, squash and amend

Last refreshed 2026-09-18.