挑选一个提交包括以前的提交?

cherry-picking a commit includes previous commits?

完成 https://learngitbranching.js.org 后,我以为我得到了 cherry-pick 的想法,但事实证明我根本没有。

我创建了一个文件 abc.txt 并进行了如下提交:

(write a) ← (write b) ← (write c)[master][HEAD]

由此 abc.txt 变为:

a
b
c

现在,在 (write a) 上创建分支 from-a

(write a)[from-a][HEAD] ← (write b) ← (write c)[master]

和 cherry-picking (write c)[master],我认为它会让 abc.txt 只包含 a 线和 c 线,即像

a
c

但实际结果为:

a
<<<<<<< HEAD
=======
b
c
>>>>>>> 3a0882d... write c

在这里,我的困惑有两个方面。为什么它会发生冲突而不仅仅是添加行?为什么它包含 b 线,即使我只挑选了 write c

Git 是上下文感知的,会查找周围的线条以及 added/removed 的线条。

这是有道理的,因为 git 需要知道应该在哪里应用提交的更改。

在您的例子中,分支 from-a 具有内容

 a

周围的行是空的。

您尝试挑选的提​​交具有如下内容:

diff --git a/abc.txt b/abc.txt
index 422c2b7..de98044 100644
--- a/abc.txt
+++ b/abc.txt
@@ -1,2 +1,3 @@
 a
 b
+c

即使提交消息在 added/removed 行周围显示更广泛的上下文,git 也只会尝试匹配上面一行和下面一行修改。 (感谢das-g

这意味着 git 将尝试查找行:

b

在文件末尾并插入行

c

之后。

由于在您的分支 from-a(当前 HEAD),git 找不到行

b

在文件末尾,因此无法干净地应用您的补丁,导致冲突。

正文

<<<<<<< HEAD
=======
b
c
>>>>>>> 3a0882d... write c

表示冲突,git看到文件末尾的实际内容什么都没有,由

表示
<<<<<<< HEAD
=======

但 git 预计会找到行

b

为了添加行

c

在它之后,由

表示
=======
b
c
>>>>>>> 3a0882d... write c

就这样,你解决冲突,决定如何加入这两个州。

当你有冲突时,你总是在<<<<<<< HEAD>>>>>>>之间寻找代码。
在它们之间,您将有 ======= 将当前 HEAD 的状态与应用补丁后 git 预期的状态分开。

cherry-pick 是合并。

提交 c 不同于 c 的基本提交,它添加了行 c.

commit a 也不同于 c 的基本提交,它删除了行 b.

                          file  [b]
                          ----
                          a
                          b


   file [a]                                  file [c]
   ----                                      ----
   a                                         a
                                             b
                                             c

由于两个更改大块重叠,Git 假定受影响的行可能是相关的,因为源代码中的语义实体通常占用多行,您可能会在一次更改中添加到一个实体并删除整个实体另一方面,第 c 行可能与第 b 行有某种关联,如果您要删除 b,您可能也不想添加 c