In the git-config documentation the information about pull.rebase:
pull.rebase
When true, rebase branches on top of the fetched branch,
Rebase is a command that's used to rewrite your commit history, and rewriting commits causes their SHA IDs to change. Rebasing your own private commits that no one else has based their own work off of (i.e. made commits on top of) is fine.
However, you run into trouble when you rebase shared public history, because other people who have the old history that you rebased are forced to sync up or redo their commits on top of the new history (which can potentially be a difficult process), or try to resolve the old history with the new one, which will certainly produce conflicts. From the official Linux Kernel Git documentation for rebase:
Rebasing (or any other form of rewriting) a branch that others have based work on is a bad idea: anyone downstream of it is forced to manually fix their history.
Thus, you should not rebase commits unless you're sure that no one else shares those commits that you're rebasing.
That said, you should really learn to rebase though, both interactively and non-interactively, because it's the most powerful and effective tool in Git's arsenal, and if you don't know how to use it, then you're not using Git effectively.
You can learn more about rebasing from the Rewriting History section of the free online Pro Git book, and of course the official Linux Kernel Git documentation for rebase is excellent as well.
Let's say you have these Git repositories:
you
, hosted somewhere;origin
, which is the main development tree.You're working on something and made two commits A and B. You published them to your public repo. In the same time, origin
has one other commit Z.
/-A-B master, you/master
o-o-o
\-Z origin/master
Now let's say one colleague needs your two commits to begin a new feature. He pulls your branch from your public repo and makes some commits on top of that.
/-C-D-E colleague/master
/-A-B master, you/master
o-o-o
\-Z origin/master
You now want to add your two, completely tested, commits on top of origin/master
. You fetch from origin
and make a rebase (which is equivalent to git pull --rebase
or git pull
with the pull.rebase option set).
That creates two new commits. You push them to your public repo and to origin
. To complicate things further, let's say a new commit F is pushed to origin
after that.
/-A-B-C-D-E colleague/master
o-o-o
\-Z-A'-B'-F master, you/master, origin/master
Now the problem is that your colleague has some work based on two "deprecated" commits, and to avoid further complications (conflicts when merging, messing up history) he must rebase his branch on top of B' (let's say he doesn't want F). You need to tell him about that, or else maybe he won't notice what you've done.
/-C-D-E colleague/master
o-o-o-Z-A'-B'-F master, you/master, origin/master
If you didn't tell him, later he would merge his branch back into origin, and the history would look like this:
/-A-B-C-D-E
o-o-o \
\-Z-A'-B'-F-M colleague/master, origin/master
You have twice the A and B commits, though with different names. The history becomes harder to read, and you will run into awful merging conflicts. And remember this example is quite simple. If there are tens of people working on the project, and origin
is moving fast, the history will soon become a complete mess.
If it's only one colleague it's probably fine. But if you can't know exactly who pulled from you, you can't know who you have to warn. It's especially true in open source development.
The main rule is: don't rebase commits you've already published. If A and B were only in your private repo, rebasing is fine and is probably the best thing to do, because it makes the history simpler and meaningful. A diverging history is only meaningful when the branch has a good reason to exist (e.g. a feature branch).
It is worth to mention that an "evil change" from an "evil merge" can be lost silently while rebasing an "evil merge" containing an "evil change" which does not conflict with other commits.