git 显示两个分支之间不同的提交的日志,包括共同的祖先

git log to show commits different between two branches, including common ancestor

在处理从我们的主要(例如,master)分支创建的功能分支(例如,feature)时,我使用以下 git 命令查看列表已添加到 feature 分支但不在 master 分支的提交:

git log --oneline master..HEAD

这会输出 feature 上不在 master 上的提交的简短摘要(请注意,在检查 feature 之后,此命令是 运行分支机构):

$ git log --oneline master..HEAD
1ca070a (HEAD -> feature) foo the bar
03a1047 baz the wuz
c9e8279 fop the sip
6ee6d6f up the ante
5812200 bop the binky

问题是,它没有显示 master 分支上的共同祖先提交。我想要的是命令再包含一行,这是共同的祖先提交,如下所示:

1ca070a (HEAD -> feature) foo the bar
03a1047 baz the wuz
c9e8279 fop the sip
6ee6d6f up the ante
5812200 bop the binky
fb37d68 (master) fuzzy the wuzzy

我希望将 master 替换为 master~1 将包括共同祖先之前的一次提交,因此包括共同祖先,

git log --oneline master~1..HEAD

但无论我指定 master 还是 master~1,日志摘要总是相同的。

$ git log --oneline master~1..HEAD
1ca070a (HEAD -> feature) foo the bar
03a1047 baz the wuz
c9e8279 fop the sip
6ee6d6f up the ante
5812200 bop the binky

我的问题是,如何在日志摘要中包含共同祖先提交? 注意,共同祖先不一定是 master 分支的尖端.

似乎没有 git 命令可以让您完全做到这一点。 master..HEAD 语法表示:

commits on HEAD but not on master

以下语句是等价的:

git log --oneline master..HEAD
git log --oneline HEAD --not master

所以特别是如果你正在处理合并提交,向 git 解释你想要排除的历史的哪一部分是很复杂的。

bash 解决方法

但是你可以告诉 git log 他应该显示多少次提交,所以用一点点 bash 魔法下面的命令应该做你想做的事:

git log --oneline -$(( $(git rev-list --count HEAD ^master) + 1))

解释:

  • $(git rev-list --count HEAD ^master) 计算自 master
  • 以来当前分支上的提交数
  • $(( num + 1 )) 将该数字加一。
  • 然后我们 运行 git log --oneline -123(123 是您分支上的提交数 + 1)

我发现这种 --boundary 经常包含 太多 提交,但是:

git log --boundary --right-only --oneline master...HEAD

应该让你接近。添加 --graph(为了完整起见,添加 --decorate,尽管您显然设置了 log.decorate)以获得更有用的东西。省略 --right-only 以获得最有用的输出。给定 --right-only,您可以将其简化为 --boundary master..HEAD,但请继续阅读以了解为什么我建议不使用 --right-only,而是使用 --graph.

这个做的有点复杂:

  • 三点语法 master...HEAD 要求 对称差异 。也就是说,我们从三个点的左侧获得所有可从 master 而不是从 HEAD 可及的提交,以及所有可从 HEAD 而不是 master 的提交在右侧。

  • --right-only 选项,如果指定,将消除左侧提交。

  • --boundary 选项将那些专门选择为 not[=106= 的提交添加回图形遍历要访问的提交集]通过对称差分算法显示。

考虑这张图,绘制时父提交在左边,子提交在右边(而不是像 git log --graph 那样父在下面,子在上面):

          C--D--E   <-- master
         /
...--A--B
         \
          F--G--H   <-- feature (HEAD)

此处的大写字母代表提交哈希 ID。提交 E 回到 C 可以从 master 到达,提交 H 回到 F 可以从 HEAD 到达(附加到名称 feature)。提交 B 是这两组提交的合并基础。

在这里,master...feature 选择左侧的提交 C-D-E 和右侧的 F-G-H。 (请注意,反转名称 - feature...master - 选择相同的提交,但现在 C-D-E 将在右侧。)因此将 --right-only 添加到此集合中几乎可以 您想要的:通过 HEAD 提交,不包括可从 master 访问的提交。这就是您从更简单的 master..feature.

中获得的 相同 输出

现在,如果我们添加 --boundary,Git 也会包含提交 B。也就是说,git log --boundary master..featuregit log --boundary --right-only master...feature 都将显示提交 B-F-G-H(以其他顺序)。

使用--decorate,当git log显示提交H时,它会添加HEAD -> feature装饰。但是commit B 没有分支名,所以不会被装饰。很难说提交 B 属于 both 个分支。

如果没有 --right-only 并且有 --boundary--graph,Git 将在 master 上显示提交 C-D-E,在功能上显示 F-G-H,与EH 修饰,并将包括边界提交 B。结果图将非常清楚地显示 B 是共享的合并基础提交。

当图形变得复杂时,--boundary 加回 太多 提交。额外的提交仍然会相当清晰地显示——无论如何,当有尽可能多的图表线时,这些东西就会变得清晰。您可以添加 --simplify-by-decoration 以帮助消除大量视觉混乱:生成的图形可能是可读的,并且可以让您识别共享提交。