为什么...和...的含义在git diff和git log之间翻转?

时间:2018-05-09 00:20:45

标签: git

以此历史图表为例:

$ git log --all --graph --oneline
* 691d454 (HEAD -> branch-b) branch-b-2
* c3bd488 branch-b
| * f5756ff (branch-a) branch-a-2
| * de00ec4 branch-a
|/  
* 5ad3b15 (root) root

现在,比较git diff branch-a..branch-b

diff --git a/f b/f
index af31a64..e7791f3 100644
--- a/f
+++ b/f
@@ -1 +1 @@
-branch-a-2
+branch-b-2

git diff branch-a...branch-b

diff --git a/f b/f
index d8649da..e7791f3 100644
--- a/f
+++ b/f
@@ -1 +1 @@
-root
+branch-b-2

git log --oneline branch-a..branch-b

691d454 (HEAD -> branch-b) branch-b-2
c3bd488 branch-b

git log --oneline branch-a...branch-b

691d454 (HEAD -> branch-b) branch-b-2
c3bd488 branch-b
de00ec4 branch-a
f5756ff (branch-a) branch-a-2

基本上,我们看到了这个:

|------+--------------------------------------+--------------------------------------|
|      | branch-a..branch-b                   | branch-a...branch-b                  |
|------+--------------------------------------+--------------------------------------|
| log  | root -> branch-b                     | branch-a -> branch-b                 |
|      | (root, branch-b]                     | [branch-a, branch-b]                 |
|      | changes introduced in branch-b       | difference from branch-a to branch-b |
|------+--------------------------------------+--------------------------------------|
| diff | branch-a -> branch-b                 | root -> branch-b                     |
|      | [branch-a, branch-b]                 | (root, branch-b]                     |
|      | difference from branch-a to branch-b | changes introduced in branch-b       |
|------+--------------------------------------+--------------------------------------|

这意味着,如果您想要查看在作为提交列表从master中分离的分支中完成的更改,git log master..branch将向您显示。但是,如果您希望将相同的更改视为组合这些提交的差异,则必须切换到...,如git diff master...branch。这是我发现自己经常做的事情,也是我一直想知道的一个小烦恼。

有设计理由吗?这似乎只是一种不一致。

编辑:为了澄清,我知道.....difflog中的转化为git diff branch-a..branch-bgit diff $(git merge-base branch-a branch-b) branch-b。我的问题可以改写为:将它们翻转以使它们彼此保持一致是不是更有意义?例如,如果git diff branch-a...branch-b表示git diff branch-a branch-bdiff表示log,那么git diff master...branch将与git log master..branch一致。那么,为什么不是这样呢?

编辑2:在表格下方的段落中,我给出了masterbranch类似的实际示例。对于另一种情况,如果要获取将git log master...branchgit diff master..branch分开的提交列表(即表示2之间差异的提交),则使用adb pull {absolute path to directory/file} cat filename ,如果你想要代表相同差异的差异,你可以使用<Type>Code39</Type>

编辑3:我试图让桌子更清晰。括号和括号的使用是math interval notation

编辑4:转换桌子使其更适合。

1 个答案:

答案 0 :(得分:0)

他们不是(翻转)。相反,..中的git diff具有 no 含义的特殊含义,而...中的git diff具有git diff唯一的特殊含义git diff 1}},在任何其他Git命令中都找不到。

您的特定输入图 ,在编辑之前:-) ...太小而无法显示真正的差异。如果你在两个分支分歧后有更多的提交,你可以看到更多。

让我们首先看一下git diff,因为它更简单。 git diff <commit1> <commit2> 在这些特定情况下做了什么 - 组合差异有特殊情况,但它们不适用于此;我们可以将提交与我们的工作树或我们的索引进行区分,我们在这里没有做 - 是选择两个单独的提交并比较它们

要命名要比较的两个提交,我更愿意写:

git diff <commit1>..<commit2>

但是,如果您愿意,可以写下:

..

这些完全相同的东西,总是。 1 Git只是假装你毕竟没有写master。无论您在此处使用哈希ID,还是使用origin/master之类的分支名称,或git diff之类的远程跟踪名称,或者这些名称的任意组合,都是如此。

请注意,两个提交名称或哈希ID的顺序很重要:git diff <commit1>...<commit2> 的输出是一组指令,告诉您如何更改第一次提交以便获得第二次提交,如果你按照所有说明进行操作。

如果你写:

git diff $(git merge-base <commit1> <commit2>) commit2

Git将比较两个提交: 2 Git将在两个给定的提交之间找到 merge base ,然后比较该合并库提交到第二个列出的提交。也就是说,这与shell样式扩展相同:

git diff

这里,和以前一样,顺序很重要:合并基础是相同的, 3 ,无论两次提交的顺序如何,但是合并基础与第二次列出的提交进行比较。 / p>

1 好吧,几乎总是!如果在命令行中列出第三个​​提交,可以发现一些极端情况,其中它就像您使用三点语法一样。我认为这些是git diff中的一个错误,尽管有人总是可以依赖它们。

2 这里还有另一个案例,肯定一个错误:如果有多个合并库,git log会产生一个组合差异。这不是三点语法的意图,这就是为什么它是一个错误。

3 这假设您没有在脚注2中发现错误。当多个提交有一个合并基础时,顺序无关紧要,但是当存在多个合并基础时,顺序为输入可能会影响输出的顺序。

对于..和大多数其他Git命令,...<commit1>..<commit2>具有完全不同的含义。毫无疑问,您现在知道<commit2> ^<commit1>git rev-parse的简写。我们可以使用$ git rev-parse master..origin/maint 468165c1d8a442994a825f3684528361727cd8c0 ^ccdcbd54c4475c2238b310f7113ab3075b5abc9c

看到这一点
origin/maint

此处master转换为第一个(未取消的)哈希ID,468165c1d8a442994a825f3684528361727cd8c0转换为第二个(否定的)哈希ID。这些告诉Git,当它遍历提交图时,它应该选择可以从ccdcbd54c4475c2238b310f7113ab3075b5abc9c(正参考)到达的提交,同时拒绝可以从git log(负参考)到达的提交。这意味着所有这样的提交,可能是许多提交。像$ git rev-parse master...origin/maint 468165c1d8a442994a825f3684528361727cd8c0 ccdcbd54c4475c2238b310f7113ab3075b5abc9c ^468165c1d8a442994a825f3684528361727cd8c0 这样的命令,遍历提交图,将显示所有选定的提交。

三点符号比较棘手,但内部翻译成同样的正面和负面参考:

origin/maint

这里,两个正面参考是与之前的mastergit merge-base相关联的哈希ID,而负参考是这些点选择的子图的点的结果 - 积分重新加入。在这个特殊情况下只有一个这样的点 - 所以这与我们将在瞬间看到的$ git merge-base master origin/maint 468165c1d8a442994a825f3684528361727cd8c0 的输出相匹配 - 尽管一些以复杂方式发散和合并的子图可以有多个这样的点:

...

(这些相同类型的复杂图形可以导致多个合并基础,但实现 C--D <-- br1 / A--B \ E--F <-- br2 的代码比找到合并基础的代码更简单。)

如果您有这样的图表:

br1...br2

三点语法C-D选择提交E-Fgit log用于执行图表的B,但选择提交F和{{ 1}}分别用于git diff(和{em>仅用于git diff)。双点语法br1..br2E-F等选择提交git log,并分别对D的提交Fgit diff进行比较(和 git diff}。