0

I learned that git pull --rebase origin master = git fetch origin master + git rebase origin/master. I am using git 2.18

But when I read this blog , It says it is not always the case.

(Please correct me from here if I understood something wrong)

The blog gives an example to show the different behaviour of git pull --rebase as otherwise we all know.

He says ,

Let's say your starting point is this:

a---b---c---d---e (origin/foo) (also your local "foo")

Time passes, and you have made some commits on top of your own "foo":

a---b---c---d---e---p---q---r (foo)

Meanwhile, in a fit of anti-social rage, the upstream maintainer has not > only rebased his "foo", he even used a squash or two. His commit chain now looks like this:

a---b+c---d+e---f (origin/foo)

A git pull at this point would result in chaos. Even a git fetch; git rebase origin/foo would not cut it, because commits "b" and "c" on one side, and commit "b+c" on the other, would conflict. (And similarly with d, e, and d+e).

What git pull --rebase does, in this case, is:

git fetch origin git rebase --onto origin/foo e foo

This gives you:

a---b+c---d+e---f---p---q---r (foo)

You may still get conflicts, but they will be genuine conflicts (between p/q/r and a/b+c/d+e/f), and not conflicts caused by b/c conflicting with b+c, etc.

I have the following doubts regarding this :

a) "A git pull at this point would result in chaos." - Why ? Since pull is non fast forward by default , won't the state become like this after the git fetch is executed. Where is the chaos ?

a---b---c---d---e---p---q---r (foo)
 \
  b+c---d+e---f  (origin/foo)

b) If a) is true , git rebase origin/foo will easily transform the graph as :

a
 \
  b+c---d+e---f  (origin/foo)
               \ 
                b---c---d---e---p---q---r (foo)

Where am I wrong ? Why he is saying git fetch origin git rebase --onto origin/foo e foo will be executed ?

Number945
  • 4,631
  • 8
  • 45
  • 83
  • As a closing comment I will conclude : `git pull --rebase origin master` = `git fetch origin master` + `git rebase --onto origin/master $fork-point HEAD`. This `$fork-point` is given to rebase by git pull code – Number945 Feb 03 '19 at 02:28

1 Answers1

0

You are correct regarding (a), but your conclusion (b) is wrong.

It is true that git rebase attempts to construct the history you depict in (b). But think how the changes b will look like when they are already part of upstream's b+c. If you are lucky, Git notice that they are and warns that the changeset is now empty. But in more typical cases, b conflicts with b+c. It is the same situation with the commits c, d, and e.

At the end (of a tedious series of conflict resolutions), you will find that all of b, c, d, and e should not have taken part in the rebase at all, and you can continue with the productive part. Finally, you arrive at the history that you actually want:

a
 \
  b+c---d+e---f  (origin/foo)
               \ 
                p---q---r (foo)

git pull --rebase saves you from this mess because it knows that your p, q, and r are the only commits that you want to rebase. Behind the scenes, it uses git merge-base --fork-point to find out that e was an upstream commit, i.e., not part of your branch.

j6t
  • 9,150
  • 1
  • 15
  • 35
  • I checked this behaviour of rebase removing redundant commits if they are squashed.Like here not taking b,c because of b+c. But results showed me that in case of squashed commits , git rebase command does not do it. Did you also checked it once ? – Number945 Jan 31 '19 at 16:19
  • Yes, I see this very often. `git rebase` cannot remove `b` automatically, because its changes are not exactly identical as any of the upstream. But sometimes Git can apply changes nevertheless: If the changes `b` are are completely independent from all of `c` to `f`, then Git can most likely apply `b` and notice that they were already applied. `git rebase` will stop and report something like _the commit is now empty._ It does not occur very often in practice, though. – j6t Jan 31 '19 at 16:25
  • Note: When and whether `git pull --rebase` or `git rebase` uses the fork-point code is a bit tricky. Assuming Git 2.18 helps since that eliminates a lot of "well, if your Git is versions X through Y, it behaves this way, but from Y through Z, it behaves this other way..." – torek Jan 31 '19 at 21:56
  • @torek I checked this behaviour in my git 2.18 and it resembles what author is saying. I am not aware how `git pull --rebase` uses fork-point or what actually is fork-point. If possible please post an in depth answer for all of us. However , I know what git pull is and basic concept on what git rebase does. – Number945 Feb 01 '19 at 10:10
  • @BreakingBenjamin: see the output of https://stackoverflow.com/search?q=%5Bgit%5D+fork-point – torek Feb 01 '19 at 10:26