A pull request sits for two days. Then someone leaves “nits” on naming and disappears. Or they approve without reading because the diff is 1,800 lines and standup is in four minutes. You did not fail at GitHub. You failed to make the review possible.
Reviewers are not lazy by default. They are optimizing for survival. A PR that is small, framed, and testable gets comments on the actual risk. A PR that is a dump of work gets silence or rubber stamps. Silence is how bugs ship. Rubber stamps are how worse bugs ship.
This is how to write a pull request that a human can finish, even on a tired afternoon.
The job of a PR is not to prove you worked
The PR is a request: please take responsibility for this change with me. That is a social document as much as a diff. The description is the briefing. The diff is the evidence. The tests are the demo.
If the description is empty, the reviewer has to reconstruct your intent from file names. They will assume the worst or skip the subtle part. If the description is a novel that restates the diff, they will skip that too. A good description is a map: why this exists, what to look at, what you are unsure about.
Size is the first review tool
Under a few hundred lines of real logic, people can hold the change in their head. Thousands of lines of generated code, lockfiles, or snapshots do not count the same, but they still hide a 20-line logic change. Call out the generated part: “Ignore package-lock.json except the uuid bump.”
If the feature is large, split by risk, not by file type. A schema migration in its own PR, then the reader, then the writer, is slower to write and faster to land. A “complete feature” PR that includes a migration, a backfill, a UI, and a flag default-on is how you get a review that misses the backfill.
Stacked PRs work if the team knows how to review them. If they do not, a sequence of merged slices is enough. Do not wait for a cathedral.
Write the description before you request review
A usable template, even if you hate templates:
- Problem: what is broken or missing for the user
- Approach: what you did, in a few sentences
- Risk: data, auth, money, delete paths
- How you tested: commands, screenshots, environments
- What you want eyes on: the part you are least sure about
“What you want eyes on” is the line that gets you a real review. People like being asked a specific question. “Does this retry loop hammer Stripe on 500s?” is reviewable. “LGTM?” is not a question.
Link the ticket. Do not make the ticket the only description. Tickets rot. The PR is what remains in git.
Screenshots and recordings are not decoration
UI changes without a picture will be reviewed as CSS soup. Show before and after. Show the empty state and the error state, not only the happy path. For API changes, show a sample request and response. For a performance fix, show the query or the trace, not a vibe.
If the change is invisible (a retry, a timeout), say how you proved it: a test, a log line, a load script. Invisible work needs extra narration.
Make the diff match the story
Do not mix a formatter run with a behavior change. The review becomes a whitespace fight. Do not “while I was here” rename a widely used function in the same PR as a payment fix. The rename will get the comments. The payment fix will not.
If you need a rename, do it first, merge, then the fix. Two boring PRs beat one clever one.
Leave TODOs only if they have an owner or a ticket. A TODO in a PR you want merged is a trap. Either do it or ticket it. Reviewers who see TODO will either block or ignore all TODOs forever.
Tests that help the reviewer
A test named it works does not help. A test named declines when the card fingerprint is on the blocklist tells the reviewer the rule. If you cannot write that test, the requirement is still fuzzy. The PR is too early, or the test harness is too weak. Say which.
If you did not add tests, say why. “Legacy module, no harness, tested in staging with order 1843” is honest. Silence reads as “I forgot.”
Delete tests that encoded the old wrong behavior. A failing test that still asserts the bug will block you. Mention the deletion so nobody thinks you gutted coverage to sneak a change.
How to ask for reviewers
Ping one or two people, not the whole engineering channel. The right reviewer is the person who owns the risk, not the person who was last active on Slack. If you need a domain expert and a product-minded reviewer, say so: “Need @sam on the SQL, @lee on the copy.”
If the PR is stuck, it is often because nobody knows they are on the hook. GitHub’s review request is the hook. A Slack message without a link is not.
Give a deadline only when it is real. “Need this for a freeze Thursday” is fair. “ASAP” is noise.
Responding to review without a duel
Assume the comment is about the code. If it is rude, the process is a separate conversation. For the code, reply with a change, a reason you will not change it, or a question. “Fixed” with no commit is how threads rot.
Do not resolve a conversation yourself if the team uses that as a signal the author agreed. Let the reviewer resolve, or follow the team rule.
Nits: if you agree, batch them in one commit. If you disagree, say you will skip and why. A PR with 40 nit threads and no decision is worse than a slightly inconsistent name.
Push back on scope. “Good idea, not this PR” is a complete sentence. Open a ticket. Reviewers who keep expanding the PR are why features never land.
Drafts, WIP, and stacked work
Draft PRs are for early design feedback. Say that. “Not for approval. Is this the right place for the hook?” If you want a full review, take it out of draft and make the description final. People skip drafts, then you get angry that nobody helped.
If CI is red, the review is optional charity. Fix CI first unless you are asking for help with the failure. Red CI plus “please review” trains people to ignore you.
After merge
A PR is not done at merge if you skipped the follow-up you promised. Flags, metrics, docs. Put the follow-up in the ticket. If the change can page someone, tell them what “bad” looks like.
Artikals exists because this social layer of engineering is usually taught by getting burned. A reviewable PR is small, honest about risk, specific about what you need, and clean in the diff. That is how you get comments on the retry loop instead of your variable names, and how you get the review this week instead of after the incident.