git diff 在文件相同时报告差异
git diff reporting differences when files are the same
我正在尝试将一些更改从一个 b运行ch 手动合并到我存储库中的另一个 b运行ch 中。我使用以下方法找出差异:
git diff branchA...branchB path/to/files > diff.patch
效果很好,展示了我所有的变化。然后我手动更新了 b运行chA 中我想要的文件并提交了它们。 Git 状态显示一切都是最新的。现在我想再次 运行 差异以确保我没有遗漏任何东西。
然而,当我 运行 差异时,它向我展示了与我第一次 运行 它时所有相同的差异。例如,它向我显示在 b运行chB 中添加的行,即使确切的行现在存在于 b运行chA 中。
我猜这是因为我手动进行了合并,但我现在如何再次获得正确的差异?
three-dot 语法 (branchA...branchB
) 在 git diff
中有一个特殊的含义,不同于它在大多数 1 中的正常含义 git 命令。
通常,X...Y
告诉 git rev-list
构建两个集合的 对称差异 :第一个集合是从 [=16 可到达的所有提交的集合=],第二个是可从 Y
到达的所有提交的集合。对称差为"all commits reachable from either X
or Y
, but not from both"。换句话说,如果追溯 X
和 Y
的历史最终得出一些共同的提交——这些提交是最低共同祖先——那么我们只剩下那些提交既不是 LCA 也不是祖先。
LCA 也就是我们所说的合并基地。在大多数情况下,只有一个 LCA,它是您确定的两个提交的(单一)合并基础。当这两个提交是两个不同分支的提示时,这很有意义,对称差异是 "commits after the merge base, on both branches",这是 cherry-picking.
等操作的一个很好的起点
不过 git diff
不太好。原因是 git diff
比较 两个并且只有两个 提交。2 如果你给它一个包含许多提交的大集合,它有不知道该怎么办。
因为 git diff
只适用于一对提交,它重新定义了 two-dot X..Y
和 three-dot X...Y
语法。对于 two-dot 版本,它只需要两个命名的提交,但对于 three-dot 版本,它做了一些聪明的事情:
git diff X...Y
表示 git diff $(merge-base X Y) Y
由于 three-dot 语法通常在(通常是单个)合并基础处停止,因此 git diff
假设您在给它提供此语法时必须打算做某事 merge-ish。因此,它会为您命名的提交找到一个合并基础。幸运的是,只有一个最低公共祖先,因此这是 the 合并基础。然后它将合并基础提交与两个命名提交中的第二个进行比较。
如果这两个名称是 branch-names(在这种情况下),并且您签出 first 分支并向其添加一个或多个提交(正如你在本例中所做的那样),我们可以确定两个 branch-tips 的合并基础没有改变。 second 分支也没有改变(因为我们只修改了第一个,向它添加了新的提交)。因此,如果我们现在 运行 一个新的 git diff
使用相同的 three-dot 语法,我们将比较 完全相同的两个提交 .
要亲自查看,请使用:
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-base),用 <
和 >
字符标记它们以显示两者中的哪一个(左或右)边)祖先选择了他们。 (将 rev-list
更改为 log --graph
以查看日志消息。)
1任何使用 git rev-list
的 git 命令。这包括 git log
(实际上,git log
和 git rev-list
本质上是相同的命令,具有不同的默认输出)。
2好吧,git 也执行它所谓的 "combined diffs" 合并提交,但您不能从 git diff
中获取一个本身。
我正在尝试将一些更改从一个 b运行ch 手动合并到我存储库中的另一个 b运行ch 中。我使用以下方法找出差异:
git diff branchA...branchB path/to/files > diff.patch
效果很好,展示了我所有的变化。然后我手动更新了 b运行chA 中我想要的文件并提交了它们。 Git 状态显示一切都是最新的。现在我想再次 运行 差异以确保我没有遗漏任何东西。
然而,当我 运行 差异时,它向我展示了与我第一次 运行 它时所有相同的差异。例如,它向我显示在 b运行chB 中添加的行,即使确切的行现在存在于 b运行chA 中。
我猜这是因为我手动进行了合并,但我现在如何再次获得正确的差异?
three-dot 语法 (branchA...branchB
) 在 git diff
中有一个特殊的含义,不同于它在大多数 1 中的正常含义 git 命令。
通常,X...Y
告诉 git rev-list
构建两个集合的 对称差异 :第一个集合是从 [=16 可到达的所有提交的集合=],第二个是可从 Y
到达的所有提交的集合。对称差为"all commits reachable from either X
or Y
, but not from both"。换句话说,如果追溯 X
和 Y
的历史最终得出一些共同的提交——这些提交是最低共同祖先——那么我们只剩下那些提交既不是 LCA 也不是祖先。
LCA 也就是我们所说的合并基地。在大多数情况下,只有一个 LCA,它是您确定的两个提交的(单一)合并基础。当这两个提交是两个不同分支的提示时,这很有意义,对称差异是 "commits after the merge base, on both branches",这是 cherry-picking.
等操作的一个很好的起点不过 git diff
不太好。原因是 git diff
比较 两个并且只有两个 提交。2 如果你给它一个包含许多提交的大集合,它有不知道该怎么办。
因为 git diff
只适用于一对提交,它重新定义了 two-dot X..Y
和 three-dot X...Y
语法。对于 two-dot 版本,它只需要两个命名的提交,但对于 three-dot 版本,它做了一些聪明的事情:
git diff X...Y
表示 git diff $(merge-base X Y) Y
由于 three-dot 语法通常在(通常是单个)合并基础处停止,因此 git diff
假设您在给它提供此语法时必须打算做某事 merge-ish。因此,它会为您命名的提交找到一个合并基础。幸运的是,只有一个最低公共祖先,因此这是 the 合并基础。然后它将合并基础提交与两个命名提交中的第二个进行比较。
如果这两个名称是 branch-names(在这种情况下),并且您签出 first 分支并向其添加一个或多个提交(正如你在本例中所做的那样),我们可以确定两个 branch-tips 的合并基础没有改变。 second 分支也没有改变(因为我们只修改了第一个,向它添加了新的提交)。因此,如果我们现在 运行 一个新的 git diff
使用相同的 three-dot 语法,我们将比较 完全相同的两个提交 .
要亲自查看,请使用:
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-base),用 <
和 >
字符标记它们以显示两者中的哪一个(左或右)边)祖先选择了他们。 (将 rev-list
更改为 log --graph
以查看日志消息。)
1任何使用 git rev-list
的 git 命令。这包括 git log
(实际上,git log
和 git rev-list
本质上是相同的命令,具有不同的默认输出)。
2好吧,git 也执行它所谓的 "combined diffs" 合并提交,但您不能从 git diff
中获取一个本身。