Git pull.rebase this is a possibly dangerous operation
Asked Answered
P

3

21

In the git-config documentation the information about pull.rebase:

pull.rebase

When true, rebase branches on top of the fetched branch, instead of merging the default branch from the default remote when "git pull" is run. See "branch..rebase" for setting this on a per-branch basis.

NOTE: this is a possibly dangerous operation; do not use it unless you understand the implications (see git-rebase(1) for details).

Could anybody describe in details what does "NOTE: this is a possibly dangerous operation; do not use it unless you understand the implications (see git-rebase(1) for details)" mean?

Providence answered 8/8, 2013 at 23:28 Comment(2)
Will anyone in your team be pulling changes directly from your copy of the repository (as opposed to a central copy that everyone pushes to)?Child
Gareth, we are using the process in the company when we have only one repository and do not support something like "forks" in GitHub.Providence
D
23

Let's say you have these Git repositories:

  • your private repo, sitting on your work computer;
  • your public repo, you, hosted somewhere;
  • a main repo, 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).

Drab answered 8/8, 2013 at 23:49 Comment(7)
Then, if you always do git pull --rebase you're on the safe side?Raindrop
If there's only one remote repo you interact with: yes, and it's probably the best practice IMHO. If you have more than one remote, then no, you have to be careful about which commits you've already pushed somewhere and might be rebased by the pull --rebase.Witchy
Note that it's probably fine if you tell everyone that one given branch you publish might be rebased at any time. This is what Julio Hamano, Git's maintainer, does with git.git's 'pu' branch: this branch doesn't follow a linear progression (it's "recreated" every time) and the documentation clearly tells you not to base a branch on top of it.Witchy
So, just to clarify, is rebasing only 'dangerous' if other people have made commits off of the commits that you rebased? If commits A and B were pushed to origin, but no one based any of their work off of them, is it safe to rebase?Dinin
@jrahhali Depends on what you mean by "pushed to origin". Did you put them in a specific branch on the remote server? And you want to rebase them on top of master? Then no, it's not dangerous. Rebasing is basically copy-pasting in this case (and resolving conflicts). But if you're pushing to the same branch the commits were in (for instance, because you edited them with git rebase -i), you'll have to force the push, and that is prone to race conditions. Now of course, if you know nobody is working on top of your commits, that's not a problem either.Witchy
Long story short: git pull rebase is only dangerous, when working on "shared repos". Is that correct?Zaibatsu
@FlorianLeitgeb "Long story short, if the commits you want to rebase have never been made public before, it's fine". That's what I'd go for.Witchy
C
11

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.

Capsular answered 8/8, 2013 at 23:37 Comment(2)
Thanks Cupcake, everything is perfectly described in the documentation, I just tried to understand are there any hidden tricks with rebasing that is not written in the documentation. The problem that I'm trying to solve is that with regular pull there are a lot of unnecessary merge commits in the repo, the --rebase option helps, but developers always forgot to use it, so I looked to some automatic way, but I'm realising that it's dangerous.Providence
Depending on your workflow, it's also probable a rebase will never be dangerous. If your developers always push and fetch from a same "central" repository, and don't publish their commits anywhere else or fetch from each other, then you can set "pull.rebase": the rebased commits will always be those which aren't published yet.Witchy
M
1

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.

Meyer answered 15/6, 2017 at 4:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.