Sometimes even experienced developers get a few details wrong.
If you look at PR 3084, you’ll see that it looks a lot like PR 2942. The commits are a little bit different, but the end results of the code are the same.
On the other hand, the commits are a little bit different, and that makes all the difference.
Make yourself a panini and prepare for a rodeo of an explanation as to why.
The Forking Path
Way back when Git was a new thing and GitHub was a new thing, I remember sitting in the State of Open Source briefing that Tim O’Reilly always convened to get opinions and advice before writing his annual OSCON keynote. I thought Git and the new development and community collaboration patterns afforded by Git and GitHub were important developments since the last keynote.
I don’t remember where I first heard the idea, but I found myself saying “forking is an act of love”.
In other words, while previously free software had seen a fork as an almost revolutionary act of seizing control of a project from maintainers taking the code and community in the wrong direction, distributed source control like Git, tla, bzr, darcs, and (earlier, svk) turned forking into an act of collaboration.
I remember sitting in a classroom at Portland State University where Greg Kroah-Hartman passed around USB sticks with a Git repository containing the Linux kernel source code around, and everyone plugged them into their laptops and made their own forks, and he walked us through contributing source code to the Linux kernel itself and it was a powerful experience.
I didn’t need Linus’s permission to make a change. I didn’t need Greg’s permission to make my own fork or make as many code changes as I wanted. This was a huge difference from the days of CVS or even Subversion (yeah yeah, you’re all making “The old man and the C programming language” jokes right now). I was the sole maintainer of my own repository and I could do what I wanted with all of the same version control powers at my fingertips as any core maintainer had.
Yet forking is only an act of love if there’s concomitant merging, and that’s where things start to get interesting.
The Rosy-Eyed Optimism of Francis Fukuyama
One nice thing about Git is that history is malleable, but the hard part about Git and pull requests is that we rarely get it right the first time, but the nice part about Git is that commits are cheap and the nice part about Git is that history is malleable.
I’ve written a few books in my day, and I’ve always appreciated a good editor. My first drafts are pretty good, but my final drafts are better. I can clean up a lot of things on my own, but having more sets of eyes and more opinions to make things better makes them better.
You can see an example of my drafts in the Modern Perl book repository, where the prose gets stronger and the teaching gets better as the drafts increase.
I’m a pretty good cook. If I put the effort into it, I can plate a good meal you’ll probably enjoy. Just don’t look at my kitchen afterwards; I’ve been accused of being a messy cook.
If all you ever saw in my books were the end results or all you ever experienced from my cooking is the food itself (and maybe the plating) but you never saw oil-spatters on my stove or a sauce stain I keep overlooking on my backsplash or a little bit of ash on the bottom of my oven or a pile of dishes in the sink I really should have washed as I was cooking, you might think the experience is magical.
It wasn’t always clean getting there, though.
I Love it When We Play Phyletic Gradualism
This brings me to PR 3084.
I’ll explain PR 2942 in an upcoming post, but the long story short is that, as usual, my Dogecoin Core collaborators had some suggestions on the code that made it better. As usual, they were right, so I made some changes. We all ended up in a place we were happy to be, but we’d taken a meandering path to get there.
For the sake of future developers (including our future selves), our strong preference is to pretend that where we ended up is always where we intended to be when we started, and the code should reflect that.
By “the code should reflect that”, I mean “let’s rewrite history to pretend we had this orderly path in mind from the start” and “let’s rewrite history to pretend we didn’t go down some side paths that turned out to be wrong”.
In Git terms, this is when you pull out the LSD chainsaw of
Rebasing a series of commits means reordering and rearranging and rewording them so that your pull request looks like an orderly series of well-planned transformations that tells an obvious and intentional story about the entire group of changes as a whole.
We do this because future Mishi and future Patrick and future chromatic and future Ed and future Alam and future you might not have all of the context of current us immediately in our heads, and we want to make all of our jobs easier to figure out what we were thinking and why.
Having a bunch of commits labeled “bugfix” or “oops” or “address review comments” makes that more difficult.
For a big change like PR 2698, that might mean turning a couple of dozen commits into a small handful.
For a smaller change like PR 2942, that means turning a small handful of commits into one or two.
Pullus Ovum Buccal; Nam Castum Esse Decet Pium Poetam
… except that we didn’t do it.
So we undid it.
But we’d already closed PR 2942, so I had to open PR 3084 with the contents we wished I’d rebased PR 2942 into.
The net effect is the same when you get Dogecoin Core 1.14.7, but history is forever. Sorry Dr. F.
We scrambled for a few minutes to undo what we did, but the alternative is living with a messy kitchen for the rest of this code’s lifetime, and we just can’t do that to future contributors (including our future selves).
So if you ever wondered why we try to be so diligent about asking contributors to squash commits into logical steps… it’s because we’re trying to be kind to our future selves.