The Pull Request, From Branch to Button
A pull request is a merge you have not run yet, wrapped in a conversation. Follow one from the branch that starts it through the description, the draft state, and the checks that run against a commit you never made.
Worth reading first: Bringing Two Histories Back Together, Your Repository Now Lives in Two Places
A pull request is a merge you have not run yet, wrapped in a conversation. Follow one from the branch that starts it through the description, the draft state, and the checks that run against a commit you never made.
A pull request is a merge you have not run yet
There is no such thing as a pull request in Git. It is entirely a GitHub construct, and underneath it is exactly one thing: please merge this branch into that branch.
Everything that makes it useful is built around that proposal. Because the merge has not happened, there is a window in which the diff can be read, commented on, argued with, tested by a robot, and changed — before it becomes part of the history everybody else works on.
# The whole prerequisite: a branch, pushed$ git switch -c fix/login-redirect# ... work, commit ...$ git push -u origin fix/login-redirect # Then either open it in a browser, or:$ gh pr create --fill # title and body from your commits$ gh pr create --web # open the form pre-filled in a browserTwo branch names define it. The base is where you want the code to go — usually main. The head or compare branch is where the code is now. GitHub shows the three-dot diff between them: what your branch adds, ignoring whatever main did while you were working.
Fork-and-pull and shared-branch are two setups
The mechanics differ depending on whether you can push to the repository, and this is the thing that makes open-source contribution look more complicated than it is.
Shared branch — you have write access
Your team's repository, or your own. Branch inside it, push, open the pull request. Base and head are both in the same repository. This is how almost all company work happens.
Fork and pull — you do not
Somebody else's project. Fork it to your account, branch in your fork, push there, and open a pull request from your fork into theirs. The base and head are in different repositories. This is how open source works, and it is the next chapter but one.
The review experience is identical. The only real differences are that a maintainer may not be able to push to your fork's branch — unless you leave "Allow edits by maintainers"ticked, which you should — and that Actions on a fork's pull request run with reduced permissions, deliberately, so a stranger cannot open a pull request that steals your repository secrets.
The description is read more often than the diff
The reviewer, the person who finds this in six months looking for why a line exists, and the release-notes writer all read the description. Only the reviewer reads the diff.
## What Quotes CSV fields per RFC 4180, so values containing commas,quotes, or newlines survive a round trip. ## Why Fixes #482. The writer joined fields with commas and nothingelse, so a company name like "Acme, Inc." produced a row withone extra column and the parser aborted the whole download. ## How - Added `quoteField()` in src/export.ts- Applied it to every field, not just strings — numbers are safe today but the type is `unknown`- Test covers comma, quote, and newline cases ## Anything to flag The export is now ~4% slower on a 50k-row file. Measured, andI think it is worth it; happy to memoise if you disagree.That last section is what separates a good description from a complete one. The reviewer cannot see what you considered and rejected, what you were unsure about, or what you know is slightly wrong. Say it, and the review becomes a conversation about the real questions rather than a hunt for them.
A description that earns a fast review
- →A title in the same imperative mood as a commit subject — it often becomes the squashed commit message
- →"Fixes #482", so the issue closes and the two are linked permanently
- →Why, not just what. The diff already says what
- →A screenshot or a short clip for anything visible. This is worth more than three paragraphs
- →How you tested it, especially if it is hard to test
- →The thing you are unsure about, stated plainly
A draft pull request says not yet, on purpose
A draft pull request is a real pull request that cannot be merged. Reviewers are not requested automatically, GitHub marks it clearly, and the merge button is disabled until you press "Ready for review".
$ gh pr create --draft --fill$ gh pr ready # mark it ready when it isIt is more useful than it sounds. Opening a draft on day one of a three-day piece of work gives you CI running on every push, a visible place for early questions, and a link to send somebody when you want a sanity check on the approach before you build the whole thing.
Fix the redirect after login
#483fix/login-redirect → main
@you opened this as a draft from fix/login-redirect
@github-actions CI queued — 3 jobs
Draft — cannot be merged
A draft is a pull request that says so. Reviewers are not requested automatically and the merge button is disabled by design.
Step through that and watch the banner at the bottom. The merge button is gated by three separate conditions, and they are checked independently: the required checks must pass, no reviewer may have outstanding "changes requested", and the required number of approvals must be met. A green tick on two of the three is still a grey button.
Checks run against the merge, not your branch
This one surprises people badly, usually at the worst moment. When GitHub runs CI on a pull request, it does not test your branch. It creates a temporary merge of your branch into the base and tests that.
Which is correct — what matters is whether the result works, not whether your branch works in isolation. It has two consequences worth knowing in advance.
Your branch can be perfect and the merge still fail, because somebody changed a function you call. Nothing is wrong with your commits.
The tested commit is a temporary merge that is not on any branch. This is why a pull request can go red without you pushing anything.
A check that is not marked required in branch protection can be red and the merge still allowed. Red is only a gate if somebody made it one.
$ gh pr checks # pass/fail for every check, in the terminal$ gh pr checks --watch # wait for them$ gh pr view --web # open the failing run's logsBefore you press “Ready for review”
- ✓Read your own diff on the Files changed tab. You will find something
- ✓No debug logging, no commented-out code, no TODO you meant to do
- ✓The branch is up to date with main, so the reviewer is not reading a stale diff
- ✓The checks are green — do not spend somebody else's time on a red pull request
- ✓The description says why, and names the thing you are unsure about
- ✓It is small. A 2,000-line pull request does not get reviewed; it gets approved
Key takeaways
- A pull request is a GitHub construct wrapping one proposal: merge this branch into that one.
- It tracks a branch, so pushing another commit updates it in place — same number, same conversation.
- GitHub shows the three-dot diff: what your branch adds, ignoring what main did meanwhile.
- Shared-branch and fork-and-pull differ only in where the head branch lives; the review is identical.
- Leave "Allow edits by maintainers" ticked on a fork's pull request.
- The description is read by more people than the diff. Say why, and say what you are unsure about.
- A draft pull request cannot be merged and does not request reviewers — good from day one of the work.
- The merge button is gated by required checks, no outstanding changes requested, and enough approvals.
- Checks run against a temporary merge with the base, not your branch, so a pull request can go red with no push.
- Small pull requests get reviewed. Large ones get approved.
Quick check
Answer these to unlock the next chapter — 3 of 4 to pass. You can retake it anytime.
Answer every question to check.
Make a free account to read on
Every chapter is free — an account is how your progress, XP, and streak follow you from your laptop to your phone, and how you show up on the leaderboard. No payment, no trial.