Hacker News new | ask | show | jobs
by dfox 5660 days ago
I simply don't see how this effort to use rebase instead of every merge helps anything. While there are valid uses for rebase I simply don't buy this "cleaner" (and incorrect) history argument.
5 comments

Git has changed how I work with and even think about a codebase, and rebase is a big part of that. Because of git's speed, the warm fuzzy security provided by its hashing mechanism, and a few other things, a new dimension (time) has opened up for organizing my ideas and experiments. Before git, committing to source control was like laying down layers in concrete. That meant going back and fixing anything was a concrete-smashing construction project, and that led to a mental model in which version history was just a documentary record: if things were originally done in order X,Y,Z, to turn that into X',Y',Z' would be to falsify history. With git I have a different mental model: the temporal dimension is no longer just a factual history (though it still is that at a large scale). It's now a medium for organizing and reorganizing things logically. It's like having a new scratch buffer in your brain.

Such a new medium is a rarity in programming and can take a long time before it finds its proper place. It seems flawed because it deviates from the "normal" way. But this new tool has led to breakthroughs in how my designs evolve, and I wouldn't give it up willingly. That's despite the fact that some of the criticisms of rebase are real: e.g. you can break previous commits without knowing it. The value of the feature far outweighs these costs, at least for the projects I've used it on. You know how Lisp programmers go on about how malleable Lisp programs are, like you're molding in clay rather than pouring concrete? It's analogous to that.

Edit: another analogy is interactivity. Rebase gives you a feedback loop into the evolution of your code the way that REPLs give you a feedback loop into its execution. Qualitatively new feedback loops are extraordinarily valuable.

Interactive rebase [git rebase -i] is useful in open source projects where you want to present your change as a logical sequence of patches. In theory at least, this helps reviewers since you can present it as "first we make this code transformation which doesn't change the semantics, second we add this new function, third ...", and each step can be checked more easily than a single large patch.

When you start out making a change, you are feeling your way through what needs to be done, and it's not until you've done some experiments that you have an idea of the logical sequence you want to present. At that point you can start to use interactive rebase to split and combine individual changes, and change the order to make up the logical story you want to tell. Then you post this as a sequence of patches for reviewers, even though it really has no relationship to how you wrote the change.

> I simply don't buy this "cleaner" (and incorrect) history argument.

Incorrect how? Incorrect in that it doesn't reflect the exact way that history was constructed locally? Spoiler: it rarely does. Every —amend, every usage of a queue (MQ, Quilt, …), every patchbomb sent to a mailing list means the history recorded won't exactly reflect the way it was created. And that's for the better: history should be crafted for sense, not for useless historical correctness.

It all depends on what you use git for. git is a great tool for revision control, but it is also a great tool for managing your own work, where it becomes closer to being an editor function than a revision control tool.

When I wrote an essay at school, I was taught to write a draft first, and sometimes a second draft. I typically wasn't expected to hand the drafts in.

When I write code in an editor, I don't save a history of every keystroke, yet I do commit often. In a way, I formalise the undo function of my editor slightly, but it becomes logical-change centric rather than keystroke-centric.

If you treat git as a tool to develop your own work as well as to manage the project revision history, then it makes perfect sense to draw the line somewhere. For work before that line (eg. experimental commits or reworking a patch for upstream submission), use rebase. For things on the other side of the line, use merge. Ruling out one side of this line entirely is just counter-productive.

Another example: git was written for open source projects. It is typically expected in these environments that patch submissions are coherent and complete. Nobody wants to see the mistakes that you correct and then fixed; they want to see patches that make sense and are easy to review. Rebasing is great for this.

I don't rebase everything. Merges still have their place.

An early draft of this post talked about the relationship between rebase and bisect, but I cut it out to focus on one topic. The tl;dr is that heavy merging makes it harder to reason about bisect (and, of course the history in general).