Don't see what the big deal is.
The more-complicated but still safe use is to rebase your local branch on top of an advanced upstream before pushing. Some people prefer merge for this case, but it is somewhat impure.
The problematic use of rebase is on pushed branches. Especially if you have collaborators.
Yep. As soon as you have a PR out, and have to address comments, you have a public branch and can't safely rebase it. So you can't roll those new changes in to the "clean" history, If upstream also has changes before your PR gets merged, you'll also have to add a merge commit anyway.
"Don't rebase public branches" is an easy way to say "if someone has built something on top your branch, don't rebase unless you expect them to also rebase." 90% of the time this is not actually harder than merging, though, and still produces a better history and more atomic commits.
At this point I'm even only 99% firm on "never rebase master", as long as release tags are truly immutable.
In my opinion, the reason for all of this is due to how `git log` shows history. If you merge a branch, then every commit in the branch is now scattered among your mainline history, making it confusing to see what is going on.
So, instead of fixing `git log`, you end up rebaseing (and possibly squashing) on top of the main branch, then doing a fast forward commit so you get a "clean, linear history".
But, if git just change the default of `git log` to `git log --first-parent`, then so much of this would go away.
Only top level commits (directly to the branch, fast-forward merged, or a merge commit) show up in the history.
Now, let's say I have a branch that I've been working on for 2 weeks. I have 20+ commits. During that time, I've already needed to merge the main branch into my branch to keep it up to date several times.
I can either rebase the whole thing, to clean up history, remove the merge commits from main, squash unnecessary changes, and so on, just so I can get a "clean" history in main, or, we can just do a merge commit bringing in my whole branch with a good commit message.
I prefer the merge commit because it is then very easy to track _all_ of the changes made in my branch by a single commit. I can do a diff on the merge commit and see all changes. I can cherry-pick just the merge commit and bring in all the changes. If I need to break down what the original developer of the branch was doing, I can walk through all the sub-commits.
There is no need for them to rewrite history and hide their workflow or their process.
But again, the problem is, by default, `git log` shows this as a huge mess, whereas `git log --first-parent` would _only_ show the merge commit, and would hide all the child commits that happened in the branch. After all, the top level merge commit is what is important, we only care about the subcommits when we need to dig in.
In the orgs I’ve worked in, it was important that mainline always (bugs notwithstanding) always be ‘runnable’. Many people (myself included) will happily commit in-progress changes to branches they’re working on. If these in-progress changes get into the mainline branch - even as a result of a merge - they become part of its history and break the ‘always runnable’ property.
Not really.
If you don’t care about the individual commits that lead to a merge (you only care about the final merge) then you could just do `git commit --amend` through the whole process. The end result would be the same.
But presumably these people (who aren’t narrowly focused on a linear history) do care. And (as you seem to be saying) sometimes you want to go down into the second parent of the merge commit.
And in that history (with just merges) there’s a bunch of random “synch. points” where they merged the original branch into theirs. Why? Maybe because it had been three hours, maybe it was the start or end of the day, or something else?
Can you look at the three-way diff and see why?
And then there are all sorts of half thought out commits and missteps that could have been edited out if they used rebase.
Using rebase does have drawbacks. But you can get back value proportional to the time you invest in it. So it’s not a simple matter of discovering that `--first-parent` is a thing and then setting an alias for that (really, you thought that would be it?).
And using merges only (including synch. merges) also has its advantages. But no, using rebase is not just about hiding pull request branches.
Hint: “git rebase -i HEAD~3” is your friend. So is “git bisect”.
I've used almost every source control system known to humans the past several decades and git for over a decade.
I've heard the git rebase preachers. I tried to get onboard with rebase.
All who read, avoid rebase at all costs at all times, always.
Rebase in my experience at work led to inexplicable conflicts several times I tried. When that happens the rebase preachers will be nowhere to be found, and you’re on your own.
Which is a particular kind of rebase except the final commit gets cherry-picked to the target branch (instead of rewriting the original branch).
Unless you've already started a follow-up branch before the first gets merged (eg. Waiting for QA, PO review etc.)
Then you at minimum will need to rebase your second branch after the first is merged. Not a disaster but it adds overhead.
Your preaching is contentless.