Skip to main content
Build

#engineering patterns#process

Atomic commits by default

The about-page bundle pushes three commits, not one. Commit A is the AboutPhotoHero component and the ten WebP assets. Commit B is the /about page route. Commit C is the nav patch, and it only happens if the nav patch actually touched files. The transparent-photo bundle pushes two: one for the asset swap, one for the card-frame strip.

There is a reason to slice this way. When something breaks in preview, I want to bisect. If the nav patch wrecked the mobile sheet but the hero rendered fine, a single mega-commit forces me to revert everything. With Commit C standing alone, git revert is one SHA and the hero stays live.

It also makes the commit history readable as a log. Six months from now I’ll scroll back and see “feat(about): add AboutPhotoHero with cursor-driven 10-frame cross-fade” sitting next to “feat(about): add /about page route.” The order reflects the build order. The component existed before the route that consumed it.

There’s a small operational cost: ship.sh has to track which staging area is dirty and which isn’t. The script uses git diff —quiet against src/components/ as the gate for Commit C, because the nav patch is best-effort and sometimes finds nothing to patch. If no changes, no commit. The script warns and moves on.

Commits are units of revert, not units of work. Slice them by what you’d want to undo separately, not by what you happened to write at the same time.