Git日志:排除来自特定合并的提交



我想弄清楚如何打印出一个git日志,在两个标签之间,排除所有在一个特定的合并提交中合并的提交。

例如

。如果我的提交日志看起来像这样:

   TAGA                                        TAGB
    |     C---F---H---K           Q---T---V     |
    v    /                      /             v
    A---B---D---G---J---L---M---O---R---U---W---X
                  /                  /
              E---I           N---P---S

并且我想a排除所有在merge-commit L上引入到主干的提交。(所以在这个例子中,我想排除C,F,H,K)。

当前我的git行是这样的:

git log --oneline --no-merges TAGB ^TAGA

将列出两个标签之间的所有提交(注意,我不包括合并提交本身,这就是为什么J,L,U &):

A,B,C,D,E,F,G,H,I,K,M,N,O,P,Q,R,S,T,V,X

有谁知道排除C,F,H &K ?即:

A,B,D,E,G,I,M,N,O,P,Q,R,S,T,V,X

没有一种便宜的、集所有功能于一体的git表达式来实现这一点。图行走代码要么只遵循--first-parent(如Vimsha的回答),要么遵循合并的所有父节点。因此,排他的^K(或^L^2或其他命名K的方式)有一个副作用,即从K而不是仅从C--F--H--K序列修剪所有可到达的提交。

我们仍然可以得到我们想要的列表,只是需要更多的工作。首先,生成感兴趣的哈希的完整列表:

tempfile1=$(mktemp)
git rev-list --no-merges TAGB ^TAGA > $tempfile1

(注意git loggit rev-list几乎是相同的命令,并且是从相同的源代码构建的;它们之间的主要区别是rev-list只打印完整的哈希id)。接下来,生成要排除的哈希的完整列表:

tempfile2=$(mktemp)
git rev-list --no-merges K ^B > $tempfile2

你如何找到B ?我想知道,你是怎么找到K的?但是一旦你找到了K,并且知道它是,比如说,L^2, BL^L^2之间的合并基,所以你可以用git merge-base和那两个名字找到它的ID。)在这个例子中,我们并不需要--no-merges,但在更复杂的例子中,我们可能也需要它和/或--first-parent。(编辑添加注释:当然我们不需要--no-merges:这是一个排除列表,合并已经被排除在外了。)

现在我们想要"在tempfile 1中找到的所有哈希值,不包括在tempfile2中的任何哈希值",执行此操作的Unix工具集命令是comm。(Linux变体要求对输入进行排序,实际上对此进行检查,因此您需要--nocheck-order来解决这个问题。comm使用的底层算法只需要文件的行以相同的顺序排列,情况就是这样。或者,您也可以对这两个文件进行排序:例如,sort -o $tempfile1 $tempfile1。但这既昂贵又不必要。

comm实用程序读取file1和file2,它们应该按词法排序,并产生三个文本列作为输出:仅在file1中的行;行只在file2;

我们需要"仅在file1中的行",即丢弃在file2中出现的行。这将是"text column 1",似乎还需要更多的后处理,但幸运的是:

-1       

-2      

-3       

所以我们将第2列和第3列删除:

comm -23 $tempfile1 $tempfile2

,这将在标准输出中生成我们希望git log显示的sha - 15的完整列表。

最后一步是将输出与git log --oneline挂钩,这很简单:
git log --oneline --stdin --no-walk

--no-walk阻止git log(或git rev-list)执行提交图遍历,这是我们想要的,因为我们正在为它提供每个提交访问的完整列表。--stdin提要是我们从comm获得的版本。

我们现在所需要的是一个小的shell打包来清理临时文件:

#! /bin/sh -e
# note the -e option -- this avoids the need for a lot of || exit
# clauses (to handle any early failures)
tempfile1=$(mktemp)
trap "rm -f $tempfile1" 0 1 2 3 15
tempfile2=$(mktemp)
trap "rm -f $tempfile1 $tempfile2" 0 1 2 3 15
git rev-list --no-merges TAGB ^TAGA > $tempfile1
git rev-list --no-merges K ^B > $tempfile2
comm -23 $tempfile1 $tempfile2 | git log --oneline --stdin --no-walk

(这都是未经测试的,当然,它省略了你想要找到的地方,或者得到作为参数,两个标签和合并提交L,你想要排除的一面,以及侧号,1或2。)

试试--first-parent

git log --oneline --no-merges --first-parent TAGB ^TAGA

文档在这里

——first-parent在看到合并提交时只执行第一个父提交。选项可以提供更好的概览特定主题分支的进化,因为合并成一个主题分支往往只是为了适应不断更新的上游此选项允许您忽略单个提交通过这样的合并进入你的历史。不能与…结合——平分。

最新更新