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.
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.
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.
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.
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).
It's a tool, and a fairly sharp double-edged one at that.
Use with care.
When it comes time for me to publish my changes, I very much do not want those unpublishable intermediary states going out into the world. Rebase lets me break apart and combine them into rational, test-passing changes that have cogent, readable commit messages instead of "blah", "blah again", "what the hell i forgot to frob the flubulizer!?", etc.
In sum, yes it's a heavy-handed tool. Yes you're "destroying" history, but often that history is extremely ephemeral and mundane and not germane to the actual meaning or effect of the change.
Well, then why not take the same care and simply create a new branch with only the "clean" commits, and then push that branch?
I don't see a need for rebase. Don't rewrite your existing history, make a new branch to push to others! Like "tags" in svn.
And just because you use rebase, doesn't mean you don't also merge. I often use git like this:
git checkout -b feature origin/master
while not done with feature:
edit, save, commit -am "added blah"
My commits are so small that I can write the entire commit message on the command-line. When feature is done from a coding perspective, I then: git rebase -i origin/master
Now I can squash together commits, possibly dropping some, re-ordering, etc. Generally, presenting my change in such a way that I have small'ish, self-contained changes that are easy to review, and with no obvious mistakes.Now that feature can be published for review. I happen to have setup gerrit for this purpose, but for git.git, you'd use format-patch and you'd email the patches, and that works well too. Each patch needs to be small enough that your reviewers aren't overwhelmed by it. (Smaller commits also help later on if someone has to git blame your code, or if they have to deal with conflicts when merging with your code.)
Rebase is also how you'd incorporate feedback to your patch series. Typically I'll put the correction on-top of my patch series, then squash it into place with rebase -i.
Finally, once your feature is done/done:
git fetch
git checkout master
git reset --hard origin/master # I use master only for integration
git merge --no-ff feature
git push origin master
Rarely, I will rebase topic onto a latter version of master, but only if I need some functionality that was added to master since I began the feature. I could merge master into feature, but that then makes feature harder to review.$0.02.
"But," you say, "I want to prepare my patch to look super-nice when I publish it to the world!" Fair enough. Then edit your meta-history since that is what the VCS will send. Right now, you can already do this in GIT by creating a specific branch and pushing only IT. Can't you? So why rebase