cherry-pick 是应用更改还是尝试合并整个文件的内容?

Does cherry-pick apply changes or try to merge the contents of the entire file?

我正在阅读 this article 关于 cherry-picking 的文章,那里有下面的图片:

但是,这张图片似乎误导了我。从我的简单测试来看,似乎不仅是差异,而且整个文件内容都被合并了。这是实验: 我有这个提交图:

A--B
 \
  C

提交 Afile.txt 中有此内容:

l1
l2
l3

提交 B 有小改动:

l1
l2-new
l3

提交 C 有小改动:

l1
l2
l3-new

所以现在我正在尝试使用 cherry-pick、

在提交 C 上重播提交 B
git cherry-pick B

我遇到了冲突,

<<<<<<< HEAD
l2
l3-new
=======
l2-3
l3
>>>>>>> C

如果仅应用更改,则不应存在。由于我在 C 提交中没有触及 l2 行,它应该可以顺利应用。我说得对吗?

Git 正在存储文件,而不是差异,所以 mb 由于行很近,git 无法正确解析它。

你最终会遇到冲突,因为更改太靠近了(就行号而言)。上下文(通常是实际差异块周围的 3 行)需要匹配,否则 Git(和其他版本控制系统)会将更改标记为冲突。由于您的示例中的部分上下文发生了变化,因此它被标记为冲突。

Git 存储文件,但它在很多地方生成和使用差异。

A diff 记录提交前后受影响行的状态;它还存储修改区域前后的一行文本。 Git 使用此信息来避免数据丢失和不一致。

假设我们在描述中具有这些名称的提交上创建了名为 ABC 的分支。

$ git diff A B -- file.txt
diff --git a/file.txt b/file.txt
index f0f2307..0acba21 100644
--- a/file.txt
+++ b/file.txt
@@ -1,3 +1,3 @@
 l1
-l2
+l2-new
 l3

我要求 Git 显示文件 file.txt 在提交 AB 之间的更改。

该格式是 统一差异格式 的变体,维基百科页面上有关于 diff utility.

的解释

简而言之,这个 diff 表示:将文件的第 2 行从 l2 更改为 l2-new 但前提是第 1 行是 l1 并且第 3 行是l3。即使只更改了文件的第 2 行,Git 也将文件的第 1 行和第 3 行包含在 diff 中。它们是第 2 行发生的更改的上下文。

备注:在这种情况下文件很小,第1-3行代表整个文件。 Git 不使用整个文件,它只保护更改前 1 行和更改后 1 行的任何行块。例如,如果文件有 20 行并且我们更改了第 12 行和第 13 行,则 diff 包含第 11-14 行。

回到我们的 diff,在提交 C 时文件看起来像:

l1
l2
l3-new

但为了应用 diffGit 希望它看起来像:

l1
l2
l3

由于未满足其期望,Git 无法安全地应用 diff 并确定这是冲突。

为什么 Git 需要上下文行?

假设在提交 C 时我们删除了第二行。该文件将如下所示:

l1
l3

然后我们挑选提交 B,并应用它引入的更改(将第 2 行从 l2 更改为 l2-new 而无需验证上下文。该文件现在看起来像:

l1
l2-new

等一下! l3在哪里?
我没有在提交 C 时删除行 l3 并且在提交 B 时我也没有触及它。 在不检查上下文的情况下应用差异会导致数据丢失。 Git 在应用差异时总是检查上下文,我想所有使用差异的程序都会这样做一样。