解决合并冲突后,“git diff”到底显示了什么?以及如何只看到新的变化?

What exactly `git diff` shows after resolving merge conflict? and how to see only the new changes?

我将分支A合并到分支B:

git checkout A
git merge B

在文件 c.txt 中发生冲突。我通过编辑 c.txt 文件来解决它。现在,在使用 git add c.txt 批准更改之前,我想先看看它们。 IE。 to 看看c.txt和分支A的区别,怎么做到的?

如果我简单地使用 git diff c.txt,它显示的内容比我想要的要多得多。它似乎同时显示了分支 B 的更改和分支 A 的更改(与它们共同的原始提交相比)。 IE。结果不同于 git add c.txt; git diff --cached c.txtc.txt 被标记为冲突时,git diff c.txt 究竟向我显示了什么?

TL;DR:您可能想要 git diff HEAD:c.txt c.txt


虽然文件被标记为“冲突”,但在 Git 的索引中有多个文件的“更高阶段”条目。事实上,这就是文件首先 冲突的含义:非冲突文件在 Git 的索引中处于“阶段零”,并且冲突文件具有阶段 1、2、and/or 3 个条目(通常全部三个)。

当文件处于这种冲突状态时,git diff 对文件执行组合差异

在文件上使用 git add 会删除更高阶段的条目,留下一个零阶段(无冲突)文件,这就是它不再以这种方式显示的原因。

Now, before approving the changes with git add c.txt I would like to see them. I.e. to see the difference between c.txt and branch A. How to do it?

我通常不会理会这个(我只是阅读组合的差异,或者 git add 文件,然后可以看到我想要的东西,而不需要任何花哨的东西——记住,你仍然可以访问其他版本的文件;只有 merge base 版本很难找到),但你 可以 做到这一点。您必须选择要比较的 c.txt 的哪两个副本:

  • 你说其中一个是某个提交中的副本 (branch A):那是 A:c.txt
  • 另一个副本由您决定:HEAD 提交中有一个,MERGE_HEAD 提交中有一个,Git 的索引中有三个,您的工作中有一个树。棘手的部分是为其中的每一个命名,但我们可以使用 the gitrevisions syntax 来完成其中的大部分。与 A:c.txt 一样,HEAD:c.txtMERGE_HEAD:c.txt 用于选择这些版本; :1:c.txt选择合并基础版本; :2:c.txt 选择 --ours 版本(从 HEAD 复制,因此应该匹配 HEAD:c.txt),:3:c.txt 选择 --theirs 版本(从 MERGE_HEAD).

因此,如果您想查看 HEAD:c.txtMERGE_HEAD:c.txt 有何不同,您可以只 运行 git diff HEAD:c.txt MERGE_HEAD:c.txt(或 git diff :2:c.txt :3:c.txt) .

不过,这对您可能最关心的问题没有帮助。工作树中 c.txt 的副本如何编辑以生成组合文件?幸运的是,我们可以只用文件名来命名那个,c.txt.

在某些情况下,此文件名可能类似于分支名称,欺骗Git。如果是这种情况,请确保您记住 -- 总是告诉 Git: 此后,所有内容都是文件名,或者至少不是选项,也可能不是分支名称。因此,如果文件未命名为 c.txt,而是命名为 main,并且:

git diff HEAD:main main

做错事,使用:

git diff HEAD:main -- main

(请注意,HEAD:main 不会被误认为是分支名称,-- 应该介于两者之间。

订单反转问题注意事项

如果您想将树内 c.txt 与分支 A c.txt 进行比较,两者:

git diff c.txt A:c.txt

和:

git diff A:c.txt c.txt

工作。这两个参数的顺序决定了哪个文件是“之前”或左侧文件,哪个文件是“之后”或右侧文件,这又决定了哪些行被删除,哪些行被添加。

在大多数情况下,如果您要求的差异与您想要的顺序“相反”,您可以简单地交换参数。但是对于:

git diff HEAD:main -- main

有一个问题:你不能交换这些。在这里,git diff -R 来拯救:-R 标志意味着 交换双方 。所以 git diff -R HEAD:main -- main 起到了作用:main 文件在左侧结束,HEAD:main 文件在右侧结束。