Write good Pull Requests

A pull request is a request for someone else's time. Two things make one good: keep it small enough to actually review, and let the description carry the "why" the diff can't. Skip them and review quietly becomes theatre.

Sefa
Sefa Tuesday, August 19th, 2025

A pull request is a request for someone else's time. That framing is the whole thing. Every PR you open is you asking a colleague to stop what they are doing, load your change into their head, decide whether it is correct, and put their name on that decision. Most bad PRs are bad because they forget this. They are written as a formality, a box to tick before merging, rather than as what they actually are: a request for attention that you are responsible for making easy to grant.

Two things make a PR good, and they are both about respecting the reviewer's time.

One concern per pull request

The first is keeping it small and focused. One PR should do one thing. A bug fix, or a feature, or a refactor, but not all three, and not the bug fix plus the unrelated cleanup you noticed along the way.

The reason is brutally practical: a reviewer can actually review a small, focused change, and cannot meaningfully review a large one. When a PR touches forty files across three unrelated concerns, what happens is not careful review. What happens is a rubber stamp. The reviewer skims it, sees that it is too big to hold in their head, trusts that you knew what you were doing, and approves. The review became theatre. The whole point of the process, a second person actually catching what you missed, quietly stopped happening, and now you have a process that costs time without providing the safety it was supposed to.

A focused PR keeps the review real. The reviewer can load the entire change into their head at once, reason about it, and catch the thing you did not see. That only works while the change is small enough to fit. So when you find yourself bundling an unrelated fix into a feature branch because it is convenient, split it. The convenience is yours; the cost lands on the person reviewing, and on the quality of the review they are able to give.

The description does the work

The second is the description, and this is where most PRs fail quietly. A diff shows what changed. It cannot show why. The reviewer can see that you modified a function, but not what problem you were solving, what approach you considered and rejected, or what they should be worried about. If the description is empty, you have forced them to reverse-engineer your intent from the code, which is slow, error-prone, and exactly the work you were in the best position to save them.

A good description carries the context the diff cannot. It says why this change exists, not just what it does, because the why is the part that is invisible in the code and the part the reviewer most needs to judge whether the approach is right. For anything visual, it includes screenshots, because asking a reviewer to mentally render your CSS from a diff is absurd when an image takes ten seconds to attach. And it tells them how to test it: the steps to verify the change actually works, so the reviewer can confirm behaviour instead of just reading code and hoping.

When the description does this work, the review gets faster and better at the same time. The reviewer spends their attention on judging your decision rather than on figuring out what your decision even was. You did the cheap part, explaining what you already know, so they can do the valuable part, catching what you do not.

Why this is worth the effort

It is tempting to treat all of this as overhead. You already understand the change; writing it up feels like work for no benefit, because to you there is no benefit. The benefit is entirely on the other side of the request, and that is the point of the framing. You are not writing the PR for yourself. You are writing it for the person whose time you are asking for.

A focused change they can actually review, with a description that tells them why it exists and how to check it, turns a PR from a thing that gets waved through into a thing that gets genuinely examined. That is the difference between a review process that catches bugs and one that just slows down merging without catching anything. The few minutes you spend splitting the branch and writing the description buy you a real second pair of eyes, which is the entire reason the process exists. Skip them and you keep the ceremony while losing the protection, which is the worst trade in the whole workflow.

How to Write Good Pull Requests | Article | Sefa's Portfolio