Git log:不包括特定合并的提交

时间:2016-11-02 16:25:31

标签: git git-log

我试图找出如何在两个标记之间打印出一个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

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

目前我的git行看起来像这样:

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

将列出两个标签之间的所有提交(注意,我不包括合并 - 提交本身,这就是J,L,U和W不存在的原因。):

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

任何帮助都将不胜感激。

2 个答案:

答案 0 :(得分:1)

没有廉价的,一体化的Git表达方式来做到这一点。图形行走代码仅在--first-parent之后(如在Vimsha's answer中)或遵循合并的所有父项。因此,排除^K(或^L^2或其他名称提交K的方法)具有修剪所有提交的副作用{{1} },而不仅仅是K序列。

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

C--F--H--K

(请注意tempfile1=$(mktemp) git rev-list --no-merges TAGB ^TAGA > $tempfile1 git log几乎是相同的命令,并且是从同一个源构建的;它们之间的主要区别是git rev-list只打印完整的哈希ID) 。接下来,生成要排除的哈希的完整列表:

rev-list

(您如何找到tempfile2=$(mktemp) git rev-list --no-merges K ^B > $tempfile2 ?我想知道,您是如何找到B的?{但是一旦您找到了K K },并且知道它是L^2BL^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中的行。这将是“文本第1列”,这似乎需要更多的后期处理,但幸运的是:

  

-1禁止打印第1列。

     

-2禁止打印第2列。

     

-3禁止打印第3列。

所以我们压制第2列和第3列:

comm -23 $tempfile1 $tempfile2

这会在标准输出上生成我们希望git log显示的完整SHA-1列表。

最后一步是将此输出挂钩到git log --oneline,这很容易:

git log --oneline --stdin --no-walk

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

我们现在需要的是一个小的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.根据需要加入这个。)

答案 1 :(得分:0)

尝试--first-parent

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

文档here

  

- first-parent在看到合并提交时仅跟随第一个父提交。查看时,此选项可以提供更好的概述   特定主题分支的演变,因为合并到主题中   分支往往只是关于从时间上调整到更新的上游   时间,此选项允许您忽略各个提交   通过这样的合并带来了你的历史。不能合并   --bisect。