git rebase vs git cherry-pick of detached branch

2020-06-28 03:28发布

问题:

I have two branches:

  1. master
  2. tmp

tmp branch is detached
I need to put tmp branch on top of master with resolving conflicts in priority of tmp

When I do

git checkout tmp
git rebase --strategy=recursive -X theirs master

I got error First, rewinding head to replay your work on top of it...

fatal: Could not parse object '0a722ac51071ecb4d00b1ef45384aac227b942a0^'  
Unknown exit code (128) from command: git-merge-recursive 0a722ac51071ecb4d00b1ef45384aac227b942a0^ -- HEAD 0a722ac51071ecb4d00b1ef45384aac227b942a0  

When I do

git checkout tmp
git cherry-pick --strategy=recursive -X theirs 0a722ac..384144a 

Works fine

What the difference or how can I do the same with rebase ?

回答1:

You're getting the rebase error because you didn't explicitly tell it which commit to start with, and because you did explicitly tell it to invoke merge, it went looking for the merge base1. To tell it not to bother, to just take the whole branch, specify --root:

git checkout tmp
git rebase --strategy=recursive -X theirs --root master

Your cherry-pick didn't do what you think it did. The .. construct means "not the commit on the left or anything reachable from it ...", in particular, in this case, it means "not 0a722ac". It didn't cherry-pick the whole branch. Since cherry-pick is built to expect single commits, you do have to explicitly specify a range, the way to do it here is to simply default the exclusion set to HEAD (since HEAD has nothing in common with tmp, nothing will be excluded):

git checkout master
git cherry-pick --strategy=recursive -X theirs  ..tmp

The asymmetry in the range specification is just a consequence of the two commands' most common usage: rebase applies to the whole of the current branch, while cherry-pick is generally used for one or more single commits..


1 not very intelligently, but rebasing branches with their own complicated merge history wholesale (linear whole-branch rebase works fine) is going to itch so very few people I doubt you'll be able to drum up much desire to help scratch it.



回答2:

A rebase is done by moving all commits after a certain commit: here after the parent of 0a722ac.

A cherry-pick take a list of commits and replicate them: 0a722ac..384144a

Since 0a722ac^ isn't accessible (that is the case, for instance, for an orphan branch, where 0a722ac would be the very first commit), rebase will fail, cherry-pick (which doesn't need to access to the parent of 0a722ac) will succeed.

See more at "How to cherry pick a range of commits and merge into another branch".