三个点的语法(
branchA...branchB
)在
git diff
中有不同于大多数 git 命令的特殊含义。通常来说,
X...Y
告诉
git rev-list
构造两个集合的
对称差异:第一个集合是所有从
X
可达的提交集合,第二个集合是所有从
Y
可达的提交集合。对称差异是“所有从
任一X
或
或Y
可达的提交,但不包括两者都可达的提交”。换句话说,如果回溯到
X
和
Y
的历史最终到达某些公共提交(这些提交是最低公共祖先),那么我们只剩下既非 LCAs 也非其祖先的提交。LCAs 是我们也称之为
合并基础。在大多数情况下,有一个 LCA 十分明显,它是您确定的两个提交的(单个)合并基础。当这两个提交是两个分支的末端时,这是很有道理的,并且对称差异是“合并基础后,在两个分支上的提交”,这是操作如 cherry-picking 的一个很好的起点。但对于
git diff
来说,这没有多大用处。原因是
git diff
只能比较
两个且仅两个提交。
2如果您给它一大堆提交,它不知道该怎么处理。由于
git diff
只使用一对提交,所以重新定义了两个点
X..Y
和三个点
X...Y
的语法。对于两点版本,它只取两个命名的提交,但对于三个点版本,它做了一些巧妙的事情:
git diff X...Y
意味着 git diff $(merge-base X Y) Y
由于三个点的语法通常停在(通常是单个的)合并基础,
git diff
假设您必须意图执行某些类似于合并的操作。因此,它找到了您命名的提交的合并基础。幸运的是,只有一个最低公共祖先,这就是
the合并基础。然后将合并基础提交与第二个命名提交进行比较。
如果这两个名称是分支名称(在本例中就是这样),并且您检出了
第一个分支并向其添加了一个或多个提交(就像在本例中一样),我们可以确信两个分支末端的合并基础保持不变。
第二个分支也没有变化(因为我们仅修改了第一个分支,向其添加了新的提交)。 因此,如果我们现在使用相同的三点语法运行新的
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
这将生成对称差异提交的列表(不包括合并基础),并使用
<
和
>
字符标记它们,以显示选择它们的两个(左侧或右侧)祖先中的哪一个。 (将
rev-list
更改为
log --graph
以查看日志消息。)
任何使用
git rev-list
的 git 命令都是一样的。这包括
git log
(实际上,
git log
和
git rev-list
本质上是相同的命令,具有不同的默认输出)。
好吧,git 还会为合并提交执行所谓的“合并差异”,但你无法从
git diff
本身获取它。
git diff
中显示出来。 - Tim Biegeleisen