Skip to content

GitHub Pull Requests

7 min readGitHub Engineering · Pull Requests

A pull request is not a Git object. It is a GitHub collaboration and review construct built around the difference between two branches.

Everything in this cluster follows from that sentence, and it is worth being stubborn about it. There is no pull request in .git/. No plumbing command reads one. Clone a repository and every pull request it has ever had is absent, while every commit those pull requests discussed is present.

What a pull request stores is a reference to two branches — a base and a head — plus the conversation, reviews, checks and policy decisions that accumulate around the difference between them. The diff is computed on demand. That is why a pull request updates itself when you push, and why closing one destroys nothing.

Start with Lesson 1

Opening a pull request is trivial. Running a repository where hundreds of them merge safely, without a human reading every line, is an engineering problem — and it is the problem this cluster exists to solve.

The twelve lessons move through three phases.

Mechanics — what a pull request is, how to create one end to end, and what draft state is for. Three lessons, mostly beginner, and the foundation for everything after.

Review — how review actually works, and then how review requirements are enforced. This is where the cluster turns from individual practice to team policy.

Governance — branch protection, rulesets, CODEOWNERS, merge queues and reviewer assignment. These are usually encountered as five unrelated settings screens. They are one system, and the cluster presents them that way.

The final lesson is a decision guide rather than a feature explanation: what actually makes pull requests work in practice, which is mostly about size, scope and response time rather than about tooling.

A pull request from branch to release

A vertical progression: a branch is created, pushed, and a pull request opened. The pull request is reviewed, required checks run, policy and rulesets are evaluated, it optionally enters a merge queue, it merges, and finally it reaches deployment or release.

BranchGit — a ref pointing at a commitPushGit — objects transferred to the remotePull requestGitHub — a record referencing two branchesReviewGitHub — approvals and requested changesRequired checksGitHub — status reported by CIPolicy / rulesetGitHub — what must be true to mergeMerge queueOptional — validates against current baseMergeGit — a commit is finally writtenDeploy / releaseOptional — downstream of the merge

Two things are worth noticing in that diagram.

Only two stages write Git objects — the push, and the merge. Everything between them is GitHub recording opinions about commits that already exist. This is why a pull request open for three weeks has cost your repository nothing: no Git state changed while it sat there.

Not every repository uses every stage. The dashed stages are genuinely optional, and a small project with one maintainer needs none of the governance layer. Adding all of it to a repository that does not need it is its own failure mode — governance has a cost in latency and friction, and that cost is only worth paying when the alternative is worse.

This cluster assumes the Git underneath. Pull requests wrap branching and merging, and a reviewer who does not understand the merge is reviewing a diff without knowing what will happen when the button is pressed.

You should be able toCovered in
Create and push a branchGit Branches Explained
Explain a three-way mergeFast-Forward vs Three-Way Merge
Say what squashing does to historySquash Merging
Describe rebase versus mergeRebase vs Merge
Resolve a conflictResolving Merge Conflicts
Create a repository and open an IssueGitHub Fundamentals

The merge-strategy lessons matter most. GitHub’s merge button offers three options that produce three different histories, and choosing between them is a repository-level decision with long consequences.

By the end of this cluster you should be able to:

  • Explain what a pull request stores, and predict its behaviour from that model.
  • Take a change from branch to merged pull request, including responding to review.
  • Use draft state deliberately rather than as a synonym for “not finished”.
  • Review code usefully — and know what approving does and does not authorise.
  • Configure required reviews, and explain why an approved pull request may still be unmergeable.
  • Distinguish branch protection from rulesets, and choose between them on current capability rather than habit.
  • Write a CODEOWNERS file that assigns ownership accurately, and explain why ownership is not load-balancing.
  • Decide whether a merge queue solves a problem you actually have.
  • Argue for a pull request size and scope policy from engineering reasoning rather than folklore.
  1. Lesson 1: 01. Pull Requests ExplainedA pull request references a base and head branch and computes the diff on demand. Learn the data model, the lifecycle, mergeability, draft state and what merging actually writes.Beginner → Intermediate12 min read
  2. Lesson 2: 02. Creating Your First PRA hands-on walkthrough from branch to merge — creating, pushing, opening a pull request, requesting review, responding to feedback, passing checks and cleaning up.Beginner10 min read
  3. Lesson 3: 03. Draft Pull RequestsDraft pull requests run checks and accept review but cannot merge. Learn when drafts help, how they affect CODEOWNERS routing and automation, and team conventions worth adopting.Beginner → Intermediate8 min read
  4. Lesson 4: 04. Pull Request ReviewsHow GitHub reviews work — comments, suggested changes, approve versus request changes, stale reviews, resolving conversations — and how to review code usefully.Beginner → Intermediate2 min read
  5. Lesson 5: 05. Required ReviewsRequired approvals, code owner review, stale-review dismissal and conversation resolution — how GitHub turns a review from a courtesy into a merge requirement.Intermediate11 min read
  6. Lesson 6: 06. Merge QueuesMerge queues fix stale validation: a PR that passed CI against an old base was never tested against what it merges into. How they work, and when a team actually needs one.Intermediate → Advanced13 min read
  7. Lesson 7: 07. Branch ProtectionBranch protection constrains what may happen to a branch — required pull requests, reviews, status checks, force-push and deletion restrictions — and how it differs from rulesets.Intermediate11 min read
  8. Lesson 8: 08. Repository RulesetsGitHub rulesets: named, layerable policy over branches and tags with bypass lists and organisation-wide enforcement — and how they differ from classic branch protection.Intermediate → Advanced11 min read
  9. Lesson 9: 09. CODEOWNERSCODEOWNERS maps paths to reviewers. Pattern syntax, why the last matching line wins, the catch-all mistake that disables every rule, and how to make owner review required.Intermediate10 min read
  10. Lesson 10: 10. Pull Request TemplatesPR templates pre-fill the description so reviewers get context. Learn template locations, multiple templates, query parameters, checklist design and the anti-patterns to avoid.Beginner → Intermediate8 min read
  11. Lesson 11: 11. Assigning ReviewersTwo mechanisms, often confused: CODEOWNERS routes review by ownership; team review assignment spreads load round-robin or by load. When to use which, and how they combine.Intermediate → Advanced10 min read
  12. Lesson 12: 12. PR Best PracticesWhat actually makes pull requests work — small focused diffs, clear descriptions, fast review, sensible merge strategy — argued from engineering reasoning rather than folklore.Intermediate → Advanced14 min read

The governance layer, in one paragraph each

Section titled “The governance layer, in one paragraph each”

The five governance lessons are easier to hold together with a one-line summary of each.

Required reviews answer how many humans must say yes, and which ones. The subtlety is what happens when the branch changes after approval.

Branch protection is the original mechanism for constraining a branch: one rule per branch pattern, evaluated on push and merge.

Rulesets are the newer layer, and they differ in kind rather than degree — multiple rulesets can target the same ref and combine, they can be enabled and disabled without deletion, their configuration is visible to anyone with read access, and they can constrain commit metadata that branch protection cannot reach.

CODEOWNERS maps paths to owners. It is a routing mechanism: it decides who is asked. Whether their approval is required is a separate policy decision, and conflating the two is the most common CODEOWNERS misunderstanding.

Merge queues solve a specific problem: a pull request that passed CI against an older base has not been tested against what it will actually land on. At low merge rates this rarely matters. At high rates it is the difference between a stable main branch and one that is broken half the day.

Several words in this cluster are used loosely in conversation and precisely here. Getting them straight prevents most of the confusion that follows.

Base and head. The base is where the change is going; the head is where it is coming from. GitHub labels them this way everywhere, and reversing them is the most common mistake when opening a pull request from the command line.

Approval is a review verdict. It is not permission to merge, and on a repository with required checks it may not even be the binding constraint.

Mergeable means Git can combine the branches without conflict. Merge state means policy permits it. A pull request is routinely one and not the other.

Check is a status reported against a commit by something outside GitHub’s core — usually CI. Checks belong to commits, not to pull requests, which is why a new push resets them.

Protected describes a branch that GitHub refuses to change in certain ways. Governed is the broader idea: protection plus rulesets plus ownership plus queueing.

Draft is a structured flag, not a title convention. Tooling can act on it, which is precisely why it exists.

Governance is usually discussed in terms of what it prevents. It is worth being equally explicit about what it costs, because that is the half teams underestimate and then route around.

Every requirement adds latency between “the work is done” and “the work is live”. One approval on a team of four might mean two hours. Two approvals plus code owner review on a busy repository might mean two days. Required up-to-date branches on a fast-moving repository can mean a change is never current long enough to merge — which is the problem merge queues exist to solve, and which is worth recognising before you reach for the queue.

That cost is paid by every contributor on every change, and it compounds:

  • Slower merges mean larger batches, because people accumulate work rather than shipping it.
  • Larger batches mean worse review, because attention does not scale with diff size.
  • Worse review means more incidents, which motivates more governance.

That loop is real and it is how well-intentioned policy makes a codebase less safe. The way out is not less governance but smaller changes, which is why PR Best Practices closes the cluster rather than opening it.

The honest position: add a requirement when you can name the failure it prevents. Remove one when you cannot.

Writing CI workflows. Required checks appear constantly, but authoring the pipelines that produce them belongs to a GitHub Actions pillar. Here, a check is a status reported by something external.

Code review as a social practice beyond the engineering essentials. Review etiquette is covered because it materially affects whether review works, but team dynamics are not the subject.

GitHub Projects and planning. Pull requests link to Issues; planning tooling is elsewhere.

Once you can run pull requests and govern a repository, the next question is doing it without clicking — which is the GitHub CLI cluster, and then the GitHub API.

Both build directly on this cluster: gh pr is the pull request lifecycle in command form, and the API cluster automates review, checks and merging.

Begin: Pull Requests Explained