没有。没有,因为提交不保存更改,它们保存快照。合并操作只查看三个快照:合并基础提交和两个分支提示提交。
我可以通过在它们各自分支中的这些文件上运行 git blame 来解决它...
至少在 Git 中,这是一个完全不同的操作。 git blame(或git annotate)命令遍历图表,一次一个提交,向后(像往常一样)比较每个父子提交对中的一些文件和行。这会在链中定位一个特定的earlier 提交,其中出现在链中last 提交中的特定行仍然出现在那个较早的提交中。 Blame 实际上对 starting 提交中的每个源代码行执行一次 - 嗯,latest 提交;也许您会称其为 end 而不是 start,但经过优化以使其快速运行。
让我们把它画成一个具体(但简单)的例子——git blame 处理更复杂的情况,包括分支合并子图,但在构建例子时我们会忽略这些。假设我们有以下内容:
I--J <-- branch1 (HEAD)
/
...--G--H
\
K--L <-- branch2
即,您当前的提交是提交J,而您运行git merge branch2。 Git 将自行定位 合并基础 提交 H,并且实际上运行两个 git diffs:
git diff --find-renames <hash-of-H> <hash-of-J> # what we changed
git diff --find-renames <hash-of-H> <hash-of-L> # what they changed
Git 现在将尝试合并这两组更改。如果文件 F 出现在所有三个提交中,H 和 J 和 L,但在所有三个提交中不同,则两个单独的差异输出将具有两个差异中 F 的一些更改。这些更改需要组合成一个更改,该更改可以应用于提交H中出现的F副本。
当这些更改重叠(触摸H 中的 F 的同一行)或邻接时(任一方更改的结尾正好位于另一边,再次引用H中F的副本),这是一个合并冲突。
我认为你想要的是一个工具,因为我们知道H-vs-J 和H-vs-L 都“触摸”了 中的某些行F,针对适当的行范围运行 git blame -L<range> H^@..J 和 git blame -L<range> H^@..L(基于 H 中 F 的副本,分别在 J 和 L 中修改) .如果J 和L 在H 中出现这些行的点上方总体上添加或删除了行,则这两个<range> 表达式可能会有所不同。
这两个git blame 将检查提交J,然后是I,然后是H(对于第一种情况)和L,然后是K,然后是H(对于第二种情况)。这些检查几乎是对称的,所以在考虑问题时,我们可以只看一个“侧面”。我们将重复该操作——但可能使用不同的行号,如上所述——另一个。因为存在合并冲突,我们知道有问题的行确实在H-vs-J 中发生了变化。因此,他们:
- 在
H-vs-I 而不是在 I-vs-J 中更改,或者
-
H-vs-I 中没有变化,但I-vs-J 中确实发生了变化,或者
- 改变了两者
H-vs-I 和 I-vs-J
所以git blame 将为范围内的每一行分配它提交I 或提交J。
提交I 和J 的时间戳 并不是这里真正感兴趣的项目。相反,提交哈希很有趣:它们确定哪些提交促成了更改。
最大的复杂性是,对于范围内的每一行,贡献可能来自一个不同的提交。由于git merge 只查看H-vs-J,可能是两行更改:
-first
-second
+1st
+2nd
实际上是在I 中将“first”替换为“1st”,然后在J 中将“second”替换为“2nd”的单行更改。
当合并中的提交范围较大时,如:
A--B--C--D--...--Y--Z <-- branch1 (HEAD)
/
...--o--*
\
o--...--o <-- branch2
从合并基本提交 * 到提交 Z 的差异可能有 30 行“更改”,其中有来自 A-B-...-Z 序列表示的 26 个提交中的 15 个的贡献。因此,您至少可能需要大量信息。
如果你能让git merge 为你运行适当的git blame 可能会很好,但你不能。你可以做的是编写你自己的工具来自动化这个:
-
假设您知道当前 (HEAD) 提交的合适说明符(它是 HEAD),并且您有一个 other 提交的说明符——在我们的简单示例中为L以上——可用,在冲突合并期间,在名称 MERGE_HEAD 下,您必须找到 merge base 提交哈希。执行此操作的命令是 git merge-base。
有一个复杂性:可能有多个合并基础。使用git merge-base --all 查找所有 合并基(默认情况下git merge 会这样做)。如果有多个,请决定如何处理。 Merge 的默认设置是合并合并基础,将结果作为临时提交提交,其哈希 ID 对您来说是无法访问的。 (如果git merge 在冲突合并期间将这个哈希 ID 保存在某处可能会很好,但事实并非如此。临时提交甚至可能一开始就没有连接到提交图;我没有t 检查。无论哪种方式,它都不可用,因此除非您修改 Git 以使其可用,否则追求这条路径没有真正意义。)除了可能选择所有合并之外,我不知道临时处理这个问题的好方法基地作为git blame 的停止点。
-
无论如何,找到一个或多个合并基础(并弄清楚在多个基础的情况下该怎么办),您现在可以让您的工具运行git blame。这里的难点在于找到正确的行号。
-
H^@..HEAD 或H^@..MERGE_HEAD 中看起来很神奇的H^@ 语法只是告诉git blame,当它到达H 的任何父提交时,它可以停止查找,这可能会加速其操作。鉴于适当的-L 限制,这可能是不必要的。这可能仍然是一个好主意——事实上,如果git blame 服从--ancestry-path,您可能也想在这里使用--ancestry-path。 (我没有对此进行测试。)这将防止git blame 走下任何可能出现在更复杂图表中的死胡同。
该工具可能会让您保持 git blame 的输出未修改。