Steven Penny 的管道传输git log --no-walk --stdin
方法是一种正确的方法,并且在最复杂的情况下(对选定的提交 ID 进行复杂过滤)是必需的。
不过,有一些技巧可以用于这种特殊情况。如果您检查(广泛的,尽管令人困惑的)文档,git rev-list
您会发现选项--left-right
、--left-only
、--right-only
、--cherry-mark
、--cherry-pick
和--cherry
。
该--left-right
选项适用于任何对称差异,即由 选择的提交A...B
,这意味着“分支A
或分支上的所有提交B
,不包括两个分支上的任何提交”。这就是git cherry
它的第一部分是如何做的:它找到对称差异上的提交。但是,git cherry
继续丢弃所有在两个分支上“相同”的提交1,然后将一侧标记为 ,另一侧标记-
为+
。该--left-right
选项将所有提交标记为<
(左侧)或>
(右侧)。
由于rev-list
是 Swiss Army Chainsaw 命令,它还具有丢弃相同提交的能力。它也有更多的能力:它可以完全丢弃一侧的提交,相同或不同。这就是我们在这种情况下想要的:丢弃“相同的提交”(这样我们只保留“不同”的提交),然后丢弃所有“左侧”提交(这样我们只保留那些在右侧但不是左侧)。我们得到前者--cherry-pick
:它只保留被认为“不同”的提交。然后我们添加--right-only
只保留右侧的那些,即,当我们说 时firstbranch...secondbranch
,只保留那些既不同又在secondbranch
...中的那些,这正是这样git cherry
做的。
因此:
git rev-list --right-only --cherry-pick firstbranch...secondbranch
生成与以下相同的提交 ID 列表:
git cherry firstbranch secondbranch
(唯一的区别是+ face0ff...
它打印的是 ,而不是+face0ff
,即+
标记后没有空格)。
这看起来很傻:git cherry
我们需要git rev-list
一堆选项、两个分支名称和三个句点,而不是四个单词和两个分支名称。我们已经输入了更多的字母来得到几乎相同的东西。所以我们可以只使用较短的命令并将其通过管道传输到git log
,但现在我们进入了棘手的部分。
git log
并且git rev-list
几乎是相同的命令
事实上,它们是从相同的源代码构建的,它们只是设置了一些不同的内部选项(如果你不命名任何其他起点,它们git log
会假装你说过)。HEAD
由于我们即将通过管道输出git rev-list
to git log --pretty='%h %ce'
,也许我们可以直接完成整个事情git log
。
果然,我们可以。我们需要所有与 with 相同的选项git rev-list
,但现在我们可以运行:
git log --cherry-pick --right-only --pretty='%h %ce' firstbranch...secondbranch
(你可能也想--no-merges
在这里——我不确定git cherry
合并有什么作用!)。
1在这种情况下,“相同性”由 的输出决定git patch-id
,它基本上会从差异中去除识别行号(并且还会去除某些空白细节)。因此,如果一个提交被挑选到另一个分支中,那么两个这样的提交通常将具有相同的补丁 ID。(如果有人必须解决合并冲突,补丁 ID 会有所不同。)