tags:

views:

62

answers:

1

This is a capture from A Visual Git Reference that explains the idea of rebase.

My understanding is as follows.

  • git is tracking the changes, so 169a6 and 2c33a has (keeps track of) the changes from commit a47c3.
  • the rebase means applying the changes to da985. As a result, f7e63 has (keeps track of) all the changes from b325c to e57cf.

Questions.

  • Is my understanding correct?
  • If so, how can we sure that the changes in 169a6 and 2c33a can be (safely) applied to at the commit da985?
  • If not, could you explain what the rebase does?
+1  A: 

The way you phrased your understanding confused me a bit. I think you may have it right, but just in case you don't, here's the way I generally think of it. When you rebase, git takes those two commits and attempts to apply them to the new base. e57cf is the result of applying 169a6's diff - that is, in simple ideal cases, git diff a46c3 169a6 and git diff da985 e57cf should produce the same output. Similarly, f7e63 should contain the same changes as 2c33a. You can think of "rebase" as a synonym for "transplant", if that helps.

Now, the changes cannot necessarily be cleanly applied. When rebase runs into a commit whose patch doesn't apply, you'll get conflicts just like with a merge, and it'll ask you to resolve them then run git rebase --continue to move them.

Hopefully it makes sense that this is really a mergey operation. There are some implementation details here, but the upshot is that git takes advantage of its merge facilities whenever it can. Although the end result is transplanting 169a6 so that it becomes e57cf, the contents of commit e57cf can be created by doing a merge of 169a6 with da985 - with the knowledge that they have a common ancestor a47c3, so a three-way merge is possible. This allows rebases to avoid conflicts some of the time you might expect them to occur.

Implementation details, if you're interested: by default, rebase uses git-format-patch to create the diffs and then applies them with git-am, with the --3way option, directing it to "fall back on 3-way merge if the patch records the identity of blobs it is supposed to apply to and we have those blobs available locally." It's also possible to tell rebase to use merge strategies internally, in which case it directly calls the merge strategy (recursive by default). Either way, it's more sophisticated than simply dumping a patch and naively applying it.

(That last paragraph is half from memory, half from skimming the source of git-rebase, and it's late at night - if someone more knowledgeable happens by, please feel free to correct any inaccuracies or omissions.)

Jefromi