Git rebase 意外的合并结果

Git rebase unexpected merge result

假设以下提交结构:

A ---- B(HEAD)
 \ 
   C

这些修订中的文件内容。

甲:

1

乙:

1
2

C:

0
1

我想将 B 合并到 C。如果我通过 git merge C 这样做,我会遇到预期的冲突。但是如果我做 git rebase C 然后 git 默默地做,没有任何冲突,但结果是意想不到的:

0
12

任何人都可以向我解释为什么会这样吗?我什至可以依赖 rebase 吗?文档说变基会在另一个提交的末尾重新应用提交。那么为什么提交在第二行添加“2”不会导致任何冲突和 "eats" 换行符呢? 你可以在这个 repo https://gitlab.com/timofei.davydik/rebase_problem.git

上测试它
git checkout test
git rebase master

在每种情况下,这些问题似乎都是由文件最后一行缺少换行符引起的,并且在面对缺少换行符时可能是 rebase 的错误。从技术上讲,当缺少最后一个换行符时,文本文件不是 "valid",我怀疑这意味着这种情况很少被测试。

我在您的示例存储库中重现了该行为 - 感谢您提供它! - 然后用相同的文件创建了一个不同的沙盒,但在每个状态的最后一行有一个换行符。

对于文件最后的换行符,合并和变基都产生了:

0
1
2

如您所料。

我认为 git merge 在您的示例中看到了冲突,因为它没有将 11\n 识别为相同,而 git rebase 看到 "insert 0 ahead of 1"继续,因为它在第一行找到 1,即使 1.

中缺少换行符

git rebase 产生 0\n12 的事实表明它从 C 中获取了 0\n1,然后从 B 中获取了 2,缺少换行符来自 12,因为它们在您的文件中丢失。

我会说 rebase 考虑 1 == 1\n 是一个错误,但除此之外,根据输入输出是合理的。

实际上,mergerebase 不会以相同的方式移动东西。所以,假设你目前站在分支 B:

  • git merge C 会将分支 C 的最高状态带到当前分支 B。例如,当您在主分支上工作并尝试汇总本地开发分支的结果时,这很有用。
  • git rebase C 会将您的完整分支 B 移动到 C 之上(作为目标目标)。为此,git 实际上会通过向后浏览您的分支找到所有特定于 B 的提交,直到他发现第一个提交对您的两个分支都是通用的(这里是 "A" 点)。然后它将重播分支B在C之上的每次提交,即:重新应用每个变更集

这首先意味着 rebase 操作不是合并操作。那么,B引入的changeset其实就是"adding a 2 right after the 1".

@@ -1 +1,2 @@
1
+2

在 "A",您的文件仅包含“1”,因此您最终会得到“1”“2”。 在 "C",您的文件包含“0”“1”,因此您将得到“0”“1”“2”。