2

So shouldn't it be equal? If I have feature and master branches, and I want to to move feature branch on top of master it would be the same as cherry picking every commit from that feature branch into master?

My thought are that it should be true, but for some reasons rebasing onto master fails with some conflicts while cherry picking every commit runs just fine.

Maroun
  • 94,125
  • 30
  • 188
  • 241
Antoniossss
  • 31,590
  • 6
  • 57
  • 99
  • [See also](https://stackoverflow.com/q/11835948/720999). – kostix Dec 11 '17 at 14:05
  • Have you verified the list of commits you would be cherry-picking is the same as the list you'd be transplanting when rebasing? You'd get the latter by running `git log --reverse feature ^$(git merge-base feature master)`. – kostix Dec 11 '17 at 14:07

2 Answers2

2

Code wise on the cherry picking branch (or the base you're rebasing on top) yes, if you cherry pick in the right order.

Differences:

  1. You'll be leaving the original branch you wanted to re-base in place
  2. You'd have two similar copies (maybe identical commits) in two places on the tree (not including the message).
  3. In cherry picking you can go in any order! If you cherry pick from the head to the branch-out you may be in trouble (rebase will apply the proper order for free)
  4. Can't squash commits

I'm guessing you cherry picked in an odd order. For example:

A->B->C
   \
     D->E

Re-basing E on C is like cherry picking from C D, then E. Post your tree and which commit there is a conflict on when re-basing, and the order you cherry picked - to see any 'problems'.

Don Branson
  • 13,631
  • 10
  • 59
  • 101
kabanus
  • 24,623
  • 6
  • 41
  • 74
2

Mostly, yes, but not exactly.

First, there are three methods by which git rebase is implemented. The interactive one, and the one with -m, literally run git cherry-pick. The non-interactive non-merge one uses git format-patch | git am internally by default, and this will occasionally produce a different result from running git cherry-pick.

Second, not every commit gets selected. In particular, git rebase generally eliminates:

  • commits that are merges;
  • commits that are "empty" (commits with no diff); and
  • commits that Git decides are already cherry-picked.1

Merges literally cannot be copied, so it just doesn't bother, except when using -p (which does not copy them after all, but instead re-performs the merges). Empty-diff commits cannot be copied via git format-patch, and in general are not required for correctness anyway, so the default is to discard them. Adding -k (keep empty) makes even the non-interactive rebase use git cherry-pick, which can copy empty-diff commits.

Finally, all variants of rebase may, depending on options, use the "fork point" code to discard some of the leading commits from the set of commits-to-be-copied. Using --no-fork-point disables this option, and it is disabled by default for some rebases, but enabled by default for others. The details are spelled out in the git rebase documentation.

Unless you are running git rebase -m or git rebase -i, the difference you see is most likely due to using git format-patch | git am. It would be useful if you could identify the specific commit that is applied differently when git am runs git apply -3 on it, vs when it is git cherry-picked, since commits where this happens are somewhat rare (I have not had time to construct an artificial example, and a real example would perhaps be more valuable).


1To make this decision, Git uses git patch-id, which you can run manually; or you can use git cherry or git rev-list to get Git to run it for you automatically. The rebase code uses git rev-list (sometimes by passing these arguments, or their equivalent, to git format-patch, sometimes using --reverse --topo-order):

git rev-list --cherry-pick --right-only --no-merges upstream...HEAD

(note the three dots, which invokes the symmetric difference selector).

torek
  • 448,244
  • 59
  • 642
  • 775