@@ · review craft @@

Atomic commits make reviewable PRs

Othman Shareef · July 6, 2026 · 6 min read · The Craft of Code Review

There are two kinds of multi-hundred-line PRs: the kind reviewers dread, and the kind that reads like a well-edited essay, because the author structured it as a sequence of commits, each one a chapter. Same total diff, wildly different review cost. The difference is a craft most teams never discuss, though the squash-versus-history argument that surrounds it flares up reliably whenever review workflow comes up.

Why structure beats size

We’ve argued smaller PRs review better, but some changes are legitimately medium-sized, and the next lever after size is order. A flattened diff mixes the mechanical with the meaningful: the rename touches 30 files, the real semantic change touches two, and the reviewer must discover which is which line by line. Commit structure is the author telling the reviewer, credibly: these 30 files are the rename; trust them as a unit; spend yourself on these two. It’s the same triage we recommend reviewers do on their side, except the author, who knows the answer, does it once for everyone.

The recipe

  • Separate refactor from behavior. The cardinal rule. “No behavior change” commits get verified structurally; behavior commits get scrutiny. Mixed, they poison each other.
  • Mechanical bulk gets its own commit (renames, formatting, codemods, generated files), labeled as such in the message.
  • Messages carry the why. As one HN commenter put it, commit messages are the developer docs for a change. “Switch to exponential backoff because the flat retry hammered the API during outages” reviews itself.
  • Curate before requesting review. Your fifty “argh, forgot this bit” commits are fine while working. git rebase -i them into the story before asking for eyes. (During review rounds, switch to append-only fixups; see the interdiff piece.)

The squash debate, defused

“Why bother if we squash-merge anyway?” Because the commits’ job is during review: they’re the author’s table of contents for the reviewer. What main’s history looks like afterward (one squashed commit, or the curated sequence) is a separate policy decision with its own trade-offs (bisectability and revert granularity vs. a linear, tidy log). Both camps can be right at their own moment in the timeline. The only losing position is chaotic commits and a flattened review.

Reviewing commit-by-commit in practice

The workflow needs tool support to stick: stepping through commits, and scoping the diff to a single commit or a span when you need to re-check one chapter. GitHub allows per-commit viewing but loses your thread positions between scopes; it’s one of the flows we built deliberately into Pyor (ours, free for individuals): pick any commit or range in a PR and the diff re-scopes to it, threads intact. Author structures the story; reviewer reads it chapter by chapter; nobody re-reads the book.

Frequently asked questions

Atomic commits or squash-and-merge: which is right?

They answer different questions. Atomic commits make the PR reviewable round by round and step by step; what lands on main afterward is a separate policy choice. Many teams do both: structured commits during review, squash (or a curated history) at merge. The mistake is letting a squash-at-merge policy become an excuse for chaotic commits during review.

What makes a commit “atomic”?

One logical change that stands alone: it has a single describable purpose, the code (ideally) builds at that point, and its message explains why. “Extract retry helper (no behavior change)” is atomic. “WIP” and “fix stuff + refactor + new endpoint” are not.

Is this worth it for small PRs?

For a 50-line single-purpose PR, one commit is atomic, and you’re done. The craft pays off from medium size upward, and especially when a refactor travels with a behavior change: separating those two into commits is the difference between a 10-minute review and a 40-minute one.

← All posts