Twenty Years of Stacking Commits — jd:/dev/blog
software, startups & open source — opinions included<br>Get posts in your inbox<br>Subscribe
⌘K
In twenty years, I’ve used four different code review tools. Each was supposed to fix the previous one. None of them changed the fundamental question they were trying to answer: what is the right unit to review?
The answer hasn’t moved. The world around it has.
I started on git format-patch and git send-email in 2006, threading patches into mailing lists the way the Linux kernel did. I moved to Gerrit at OpenStack when it arrived. I tried to bring its workflow to GitHub myself, and failed. I watched GitHub turn every branch into a wall. And now I’m watching agents push code faster than humans can read it. Each era taught me the same thing: the unit of review is the commit. We just spent a decade pretending otherwise.
= 1.6' on the XCB mailing list, signed by Julien Danjou, with a unified diff inline."><br>[PATCH 2/5] from a patch series I sent to the XCB mailing list in 2010. Each patch was its own review unit. Stacking has been here the whole time.
Gerrit got it right
OpenStack ran on Gerrit. Google had built it in 2008 for Android, the brainchild of Shawn Pearce as a fork of Guido van Rossum’s Rietveld. Projects looking for serious code review followed.
Every commit you pushed got a Change-Id, a SHA-like footer Gerrit used to track that commit across rebases. One Change-Id was one review. Push six commits, get six review threads. Amend one and the others stayed untouched. Reviewers commented on the commit they cared about and ignored the rest.
The UX was hostile. You pushed code with git push HEAD:refs/for/master, a syntax that felt designed to keep newcomers out. Discussions happened in a web UI that loaded slowly even on fiber, or over a JSON-over-SSH API for the brave. You clicked through three screens to leave a comment. Senior contributors had Vim macros to make it bearable. Newcomers gave up.
But the model underneath was right. Each commit was a thought, and each thought got reviewed on its own terms. When you submitted a five-commit feature, reviewers could approve the refactoring commits while still arguing about the new abstraction in the last one. The work moved forward in pieces. Nobody waited for everything to be perfect before anything could land.
Compare this to what most teams do now. A reviewer opens a 1,500-line PR, scrolls for a while, picks a few things to comment on, and either approves or sends it back as a single block. There’s no granularity because the unit doesn’t allow it.
Gerrit knew this in 2008. It just didn’t know how to make people enjoy it.
git-review proved the UX was the wall
OpenStack built git-review to wrap Gerrit’s six-step push ritual in one command. git review did the right things in the right order. Fetch the latest target branch, rebase your commits on top, validate Change-Ids were present, push to the magic ref, print the URLs of the resulting reviews. That was it.
It got adopted across OpenStack within months. Within a year it was the default step in every contributor tutorial. Not because the tool was clever (it wasn’t), but because the friction it removed was the difference between people contributing and people giving up after their first push.
That was the lesson I carried out of OpenStack. A tool can have the right semantics and still lose if the UX is hostile. UX isn’t decoration. It’s part of correctness. The model that wins is the one a tired developer at 6pm can use without thinking. Gerrit’s model was right, but its surface area pushed everyone toward GitHub the moment GitHub got good enough.
GitHub turned every branch into a wall
GitHub got good enough around 2014. Faster UI, easier setup, and a model anyone could understand: one branch, one pull request. That model worked for solo contributions and small features. It collapsed the moment you tried to ship anything in pieces.
The problem is structural. GitHub’s PR is anchored to a branch. If you want five reviewable units, you need five branches. Each one rebased on the previous. Each one’s PR retargeted when the one below it lands. If the bottom of the stack changes, you rebase the world. Nobody does this. People give up and ship one giant PR instead, or they ship one PR per day for a week and pretend it’s fine.
I ranted about exactly this in 2013, back when most of the industry was busy convincing itself GitHub had solved code review. The argument hasn’t aged. GitHub’s PR model fights you the moment you try to ship more than one thought at a time.<br>Rant about Github pull-request workflow implementationOne of my recent innocent tweet about Gerrit vs Github triggered much more reponses and debate that I expected it to. I realize that it might be worth explaining a bit what I meant, in a text longer t
I tried to fix it myself in 2016 with git-pull-request, a small Python CLI that turned commits on a single branch into chained GitHub PRs. It worked...