为什么这个樱桃挑选有冲突?

L_K*_*L_K 16 git cherry-pick git-cherry-pick

我知道这git cherry-pick是一个用于应用指定提交更改的命令,但我认为我并不真正理解它的工作方式.

让我们说一个像这样的回购行为:

git init

echo a>a
git add .; git commit -am 'master add line a'

git checkout -b dev
echo b>>a
git commit -am 'dev add line b'
echo c>>a
git commit -am 'dev add line c'

git checkout master

git cherry-pick dev
Run Code Online (Sandbox Code Playgroud)

我认为cherry-pick命令会运行良好并将文件更改a为:

a

c
Run Code Online (Sandbox Code Playgroud)

但实际上我得到了以下信息:

error: could not apply 08e8d3e... dev add line c
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'
Run Code Online (Sandbox Code Playgroud)

然后我跑:

git diff
Run Code Online (Sandbox Code Playgroud)

输出:

diff --cc a
index 7898192,de98044..0000000
--- a/a
+++ b/a
@@@ -1,1 -1,3 +1,6 @@@
  a
++<<<<<<< HEAD
++=======
+ b
+ c
++>>>>>>> 11fff29... abc
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:为什么会出现像git-diff这样的冲突?在这种情况下,樱桃挑选工作的细节是什么?

Von*_*onC 21

再试试你摘樱桃:

git config merge.conflictstyle diff3
Run Code Online (Sandbox Code Playgroud)

您将获得更详细的差异:

<<<<<<< HEAD
||||||| parent of 5b2a14c... dev add line c
b
=======
b
c
>>>>>>> 5b2a14c... dev add line c
Run Code Online (Sandbox Code Playgroud)

它表明,当应用由dev's HEAD(bc)表示的补丁时,Git不知道共同的祖先; 它推迟到:

  • 樱桃挑选提交的直接父级(显示它在一行c之后添加一行' b')
  • 目标提交(根本不显示任何行b,可以应用添加的更改' c')

因此冲突.

采摘樱桃不像合并(它寻找合并基础).

Cherry-picking接受提交并应用它引入的更改.

这里引入的变化是:添加c在上面b.
并且目标提交根本没有b,所以对于Git:

  • 上游(目的地)提交已经"删除b"(或者从来没有在第一时间使用它,这就是这种情况,但Git不知道这一点),
  • 源提交有一个b顶部c添加.

至于Git在尝试应用该补丁时所知道的(这就是git cherry-pick:应用补丁.它根本不寻找樱桃选择提交的历史记录),这是一个冲突:并发修改.

如果您确定解决方案应该采用的方式,您可以:

> git cherry-pick -Xtheirs dev
[master 7849e0c] dev add line c
 Date: Wed Aug 17 08:25:48 2016 +0200
 1 file changed, 2 insertions(+)
Run Code Online (Sandbox Code Playgroud)

然后,您将看到bc添加到原始提交中,没有任何冲突(因为您指示了如何使用选项' -Xtheirs'传递给默认合并策略recursive来解决它)

  • 我在回复你的其他回复中提到了这一点,但是:``git cherry-pick`*确实*实际上使用了合并库并进行了三向合并.这里的问题是,在许多(但不是全部)案例中,合并基础本身是虚假的,因此没有帮助,甚至可能是有害的.这意味着Git尝试一种简单的"直接补丁"方法*首先*.如果失败,它将回退到使用樱桃挑选的提交的父提交作为合并基础.偶尔这会允许补丁正确应用,特别是如果该"基础"确实在当前历史中. (2认同)