我正在尝试将一些更改从我的存储库中的一个分支手动 merge 到另一个分支。我使用以下方法找出差异:
git diff branchA...branchB path/to/files > diff.patch
效果很好,显示了我的所有更改。然后我去手动更新了我想要的 branchA 中的文件并提交了它们。 Git status 显示一切都是最新的。现在我想再次运行差异以确保我没有遗漏任何东西。
但是,当我运行 diff 时,它显示了与我第一次运行时相同的所有差异。例如,它向我显示了在 branchB 中添加的行,即使确切的行现在存在于 branchA 中。
我猜这是因为我手动进行了 merge ,但我现在如何再次获得正确的差异?
最佳答案
三点语法 ( branchA...branchB
) 在 git diff
中有特殊含义这与大多数 1 git 命令中的正常含义不同。
通常,X...Y
告诉git rev-list
构造两个集合的对称差异:第一个集合是所有可从X
到达的提交的集合,第二个是可从 Y
到达的所有提交的集合.对称差异是“所有提交都可以从 either X
or Y
到达,但不能同时从两者到达”。换句话说,如果追溯 X
的历史和 Y
最终到达一些公共(public)提交(这些提交是最低公共(public)祖先)然后我们只剩下既不是 LCA 也不是祖先的提交。
LCA 也就是我们所说的 merge 基地。在大多数情况下,只有一个 LCA,它是您确定的两个提交的(单一) merge 基础。当这两个提交是两个不同分支的提示时,这很有意义,对称的差异是“在 merge 基础之后,在两个分支上提交”,这是像 cherry-picking 这样的操作的一个很好的起点。
对git diff
没多大用处| , 尽管。原因是 git diff
比较两个而且只有两个提交。2如果你给它一大堆很多提交,它不知道该做什么。
因为 git diff
仅适用于一对提交,它重新定义了双点 X..Y
和三点 X...Y
语法。对于双点版本,它只接受两个命名的提交,但对于三点版本,它做了一些聪明的事情:
git diff X...Y
表示 git diff $(merge-base X Y) Y
由于三点语法通常在(通常是单个) merge 基处停止,git diff
假设你在给它这个语法时一定打算做一些类似 merge 的事情。因此,它会为您命名的提交找到一个 merge 基础。运气好的话,只有一个最低公共(public)祖先,所以这是 merge 基础。然后它将 merge 基础提交与两个命名提交中的第二个进行比较。
如果这两个名称是分支名称(在本例中),并且您 checkout 第一个 分支并向其添加一个或多个提交(在本例中) ,我们可以确定两个分支提示的 merge 基础是不变的。 第二个 分支也没有改变(因为我们只修改了第一个分支,向它添加了新的提交)。因此,如果我们现在运行一个新的 git diff
使用相同的三点语法,我们将比较完全相同的两个提交。
要亲自查看,请使用:
git merge-base branchA branchB
并记下打印的提交 ID,然后查看 branchA
并添加一个提交并运行相同的 git merge-base
命令。您可能还想运行 git rev-parse branchA
和 git rev-parse branchB
添加新提交之前和之后:你会看到 branchA
在 branchB
时获取新的提交没有。
您还可以运行:
git rev-list --left-right branchA...branchB
这将生成对称差异提交列表(不包括 merge 基),用 <
标记它们和 >
字符以显示两个(左侧或右侧)祖先中的哪一个选择了它们。 (将 rev-list
更改为 log --graph
以查看日志消息。)
1任何使用 git rev-list
的 git 命令, 反正。这包括 git log
(事实上,git log
和 git rev-list
本质上是相同的命令,具有不同的默认输出)。
2好吧,git 也为 merge 提交做了它所谓的“组合差异”,但你不能从 git diff
中得到一个。本身。
关于git diff 在文件相同时报告差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35028333/