Git 将行添加到不同位置会导致樱桃拾取冲突

Git 将行添加到不同位置会导致樱桃拾取冲突,git,version-control,git-cherry-pick,Git,Version Control,Git Cherry Pick,我的分支机构是: 0x1---->0x2---->0x3 /\ /\ | | master dev 共同祖先是0x1 我会挑选一个特性来掌握 场景1: Master branch have a.txt file. 0x1 first commit. a.txt content: 1 Then I create a branch dev, I add "2" to a.txt, 0x2 se

我的分支机构是:

0x1---->0x2---->0x3
/\              /\
|               |
master          dev
共同祖先是0x1

我会挑选一个特性来掌握

场景1:

Master branch have a.txt file.
0x1 first commit.
a.txt content:
1

Then I create a branch dev, I add "2" to a.txt,
0x2 second commit
0x1 first commit

a.txt content:
1
2

Then I add "3" to a.txt
0x3 third commit
0x2 second commit
0x1 first commit

a.txt content:
3
1
2

I cherry-pick 0x3 to master:
master> git cherry-pick 0x3
它没有冲突

场景2: 但我修改了附加的位置

0x3 third commit
0x2 second commit
0x1 first commit

a.txt content:
1
2
3
我将0x3应用于master。这将产生冲突


第一场和第二场有什么不同?我糊涂了

您的cherry pick会得到一个合并冲突,因为同一个合并会得到一个合并冲突。这是因为樱桃拾取是一种合并操作。只是专门选择了cherry pick的合并基,最终提交是普通的单亲提交,而不是双亲合并提交

我认为,当使用
gitmerge
时,冲突本身更容易解释。假设我们有以下一系列提交:

          I--J   <-- branch1
         /
...--G--H
         \
          K--L   <-- branch2
我想通过将特殊名称
HEAD
附加到所选分支名称来表示这种情况,如下所示:

          I--J   <-- branch1
         /
...--G--H
         \
          K--L   <-- branch2
假设
J
L
版本为:

The quick brown fox
sometimes jumps over
the lazy dog.
以及:

两个差异以不兼容的方式改变了第2行。Git不知道要进行哪些更改,所以根据您对它的看法,它不进行任何更改,也不进行任何更改,或者两者都进行更改,然后声明合并冲突并让您清理混乱

你的樱桃 [注意:这已被修改为在更新的问题中使用提交图。我们现在使用以下内容创建存储库:

mkdir tcherry && cd tcherry && git init
echo 1 > a.txt && git add a.txt && git commit -m 0x1
git checkout -b dev
echo 2 >> a.txt && git add a.txt && git commit -m 0x2
然后在
a.txt
顶部插入
3
,或将其添加到
a.txt
的末尾,以生成两种场景的设置:

printf "3\n1\n2\n" > a.txt && git add a.txt && git commit -m 0x3
git checkout master
git cherry-pick dev
或:

第一种方法没有冲突;第二种方法产生冲突。]

在您的情况下,您使用的不是
git merge
,而是
git cherry pick
。但樱桃采摘仍然是一种融合。而不是:

          I--J   <-- branch1
         /
...--G--H
         \
          K--L   <-- branch2
A
C
的区别取决于您使用的是这两种场景中的哪一种

以下是非冲突案例的区别:

$git diff:/0x2:/0x3
diff——git a/a.txt b/a.txt
索引1191247..0571a2e 100644
---a/a.txt
+++b/a.txt
@@ -1,2 +1,3 @@
+3
1.
2.
这表示在读取
1
的行之前添加
3
,该行是第1行,变为第2行。所以Git应该删除读取
2
的行,这是合并基础版本中的第2行。Git可以安全地执行此操作,因为它知道在何处执行此操作,并且不会触及第
1行本身:只影响从2到文件末尾的行。Git还应该在行读取
1
之前插入行读取
3
。这会从文件的开头(“第0行”)到第1行产生影响。受影响的测线范围不重叠,测线读数
1
位于它们之间,使它们也不会相互“接触”

现在,让我们看一看发生合并冲突的案例:

$git reset--hard HEAD^#丢弃樱桃采摘
头部现在位于2b4180d 0x1
$git checkout-q dev
$git reset--硬头^#放弃提交0x3
头部现在位于1160130 0x2
$echo 3>>a.txt&&git添加a.txt&&git提交-m 0x3
[dev c546f74]0x3
1个文件已更改,1个插入(+)
$cat a.txt
1.
2.
3.
$git签出主机
切换到“主”分支
同样,我们现在正在提交
A
,我们将指示Git选择提交
C
(subject
0x3
),其父级是
B
。从
B
A
的差异仍然是“删除行读数2”(在第2行)。让我们看看这次从
B
C
的差异:

git差异:/0x2:/0x3
diff——git a/a.txt b/a.txt
索引1191247..01e79c3 100644
---a/a.txt
+++b/a.txt
@@ -1,2 +1,3 @@
1.
2.
+3
Git现在应该将删除行读取
2
与添加行读取
3
结合起来。第一个接触到第2行(将其完全移除)。第二行在第2行之后添加一行

Git当然可以将它们结合起来,但是“这是冲突吗”算法不喜欢两个差异都影响第2行的事实。这些差异在两个变更之间没有一条线,将变更彼此分开。所以我们得到了一个冲突:

$git cherry pick dev
自动合并a.txt
冲突(内容):在a.txt中合并冲突
错误:无法应用c546f74。。。0x3
提示:解决冲突后,标记更正的路径
提示:使用“git add”或“git rm”
提示:并使用“git commit”提交结果
检查遗留下来的
a.txt
,我们看到:

$cat a.txt
1.
>c546f74。。。0x3
请注意,我已将
merge.conflictStyle
设置为
diff3
,因此我得到了“
”行的父项,显示了冲突的内容。将其与默认样式进行比较:

$git checkout-m——冲突合并a.txt
重新创建了1个合并冲突
$cat a.txt
1.
>他们的

我个人觉得这更神秘。在像这样的樱桃采摘的情况下,从
B
A
的差异“向后”这一事实意味着我们删除了第2行。这构成了冲突的一部分。从
merge
风格冲突来看,这一点并不明显;在
diff3
样式中,我可以看到合并基础版本有一行读取
2
,我已经删除了该行。他们在添加行
3

时保留了第2行。结构不是a->b(dev),a->c(master)。我在问题的顶部位置添加了一个分支结构图。a->b->c(开发),a(主)。你能详细解释一下“直线范围是半开区间”吗?啊,好的。让我修改一下答案,因为有可能范围不是半开放的,没有冲突是出于其他原因。非常感谢!现在,我明白了为什么会产生冲突。我也知道git cherry如何选择我们对targe分支机构的承诺。我还需要圣
mkdir tcherry && cd tcherry && git init
echo 1 > a.txt && git add a.txt && git commit -m 0x1
git checkout -b dev
echo 2 >> a.txt && git add a.txt && git commit -m 0x2
printf "3\n1\n2\n" > a.txt && git add a.txt && git commit -m 0x3
git checkout master
git cherry-pick dev
echo 3 >> a.txt && git add a.txt && git commit -m 0x3
git checkout master
git cherry-pick dev
          I--J   <-- branch1
         /
...--G--H
         \
          K--L   <-- branch2
  B--C   <-- dev
 /
A   <-- master (HEAD)