【问题标题】:How to invert `git log --grep=<pattern>` or How to show git logs that don't match a pattern如何反转 `git log --grep=<pattern>` 或如何显示与模式不匹配的 git 日志
【发布时间】:2011-08-01 21:54:08
【问题描述】:

我想使用git log 来显示所有与给定模式不匹配的提交。我知道我可以使用以下内容来显示所有匹配模式的提交:

git log --grep=<pattern>

如何反转匹配感?

我试图忽略消息中“撞到版本...”的提交。

编辑:我希望我的最终输出非常详细。例如git log --pretty --stat。所以git log --format=oneline 的输出对我不起作用。

【问题讨论】:

标签: git git-log


【解决方案1】:

Git 2.4+ (Q2 2015) 可以做到这一点:参见commit 22dfa8a by Christoph Junghans (junghans)

log:教--invert-grep选项

"git log --grep=&lt;string&gt;" 仅显示与给定字符串匹配的消息的提交,但有时能够仅显示具有某些消息的提交是有用的(例如“给我看不是 FIXUP 提交”)。

最初,我们在grep_opt 中有invert-grep 标志,但是因为“git grep --invert-grep”除了与“--files-with-matches”结合使用之外没有意义,后者已经被“--files-without-matches”覆盖,它已将其移至修订结构。
在那里设置标志可以更好地表达功能的功能。

当新插入的两个测试运行时,历史将有提交消息“initial”、“second”、“third”、“fourth”、“fifth”、“@” 987654338@" 和“Second”,按此顺序提交。
与“th”或“Sec”不匹配的提交是“second”和“initial”。对于不区分大小写的情况,仅匹配“initial”。

--invert-grep

将提交输出限制为具有与--grep=&lt;pattern&gt; 指定的模式不匹配的日志消息。

例子:

我首先在其中包含“sequencer”的 grep 消息:

vonc@voncm C:\Users\vonc\prog\git\git

> git log -2 --pretty="tformat:%s" --grep=sequencer
Merge branch 'js/sequencer-wo-die'
sequencer: ensure to release the lock when we could not read the index

如果我想要带有 no 序列器的消息:

> git log -2 --pretty="tformat:%s" --grep=sequencer --invert-grep
Second batch for 2.11
Merge branch 'js/git-gui-commit-gpgsign'

【讨论】:

  • 嗯,对我不起作用:“无法识别的参数:--invert-grep。这是 git 2.9.2.windows.1。
  • @KentBoogaart 你输入了什么命令?我刚刚在 git/git cloned repo 中成功使用(windows,git 2.10.1)git log -5 --pretty="tformat:%s" --grep=sequencer:它工作得很好。
  • @Kent 我已经编辑了答案以说明 invert-grep 也可以正常工作。再说一遍,你使用了什么确切的命令?
  • @VonC 啊,是的,我没有意识到这是一个开关。我在做--invert-grep=foo。现在这对我有用,尽管它没有我希望的那么有用。能够在一个命令中指定“包含这个并且不包含这个”会很好。谢谢!
【解决方案2】:

正如 VonC 所说,最好的选择是您可以更新到 Git 2.4.0(目前在 RC2 上)。但即使你不能这样做,也没有理由编写复杂的脚本。 A (gnu) awk one-liner 应该这样做。 git log 具有有用的 -z 选项,可以通过 NUL 字符分隔提交,这使得解析它们变得容易:

git log -z --pretty --stat | awk 'BEGIN{ RS="\0"; FS="\n\n" } !match($2, /<pattern>/)'

如果您没有 gnu awk,您可能至少应该安装它。或者将此脚本移植到您的特定 awk 版本,我将其作为练习留给读者;-)。

【讨论】:

    【解决方案3】:

    与 thebriguy 的回答一样, grep 也有一个 -z 选项,可以使其能够处理以空字符结尾的字符串而不是行。这就像反转匹配一样简单:

    git log -z --color | grep -vz "bumped to version"
    

    为了安全起见,您可能只想在提交消息中匹配。要使用 grep 执行此操作,您需要使用珍珠表达式来匹配以空字符结尾的字符串中的换行符。跳过标题:

    git log -z | grep -Pvz '^commit.*\nAuthor:.*\nDate:.*\n[\S\s]*bumped to version'
    

    或者用颜色:

    git log -z --color | \
      grep -Pvz '^.....commit.*\nAuthor:.*\nDate:.*\n[\S\s]*bumped to version'
    

    最后,如果使用 --stat,您还可以匹配此输出的开头以避免匹配包含提交字符串的文件名。因此,该问题的完整答案如下所示:

    log -z --color --pretty --stat | \
      grep -Pvz '^.....commit.*\nAuthor:.*\nDate:.*\n[\S\s]*?bumped to version[\S\s]*?\n [^ ]'
    

    请注意,grep -P 在我的手册页中被描述为“高度实验性”。使用 pcregrep 代替使用 libpcre 可能会更好,请参阅 How to give a pattern for new line in grep?。虽然 grep -P 对我来说很好用,但我不知道 pcregrep 是否有 -z 选项或等效选项。

    【讨论】:

    • grep -z 在 OSX 上意味着读取 zip 压缩输入,而不是处理空终止符。
    • 对,-z 和 -P 不是 POSIX。很可能这只适用于 GNU grep。
    • 如果你想要 grep 中的 -z 选项,请在 OS X 上安装 gnu 核心工具。我更喜欢这个答案而不是接受的答案,因为您可以为 git log 指定任何额外的选项:pattern=$1; shift; git log -z --color "$@" | grep -vz "$pattern" | tr '\0' '\n' | less -r
    【解决方案4】:

    一个相对简单但具有很大灵活性的方法是使用带有 -z 选项的 git log 通过管道传输到 awk。 -z 选项在提交记录之间添加空值,因此可以轻松地使用 awk 进行解析:

    git log --color=always -z | awk -v RS=\\0
    

    (当输出为管道时,需要 color=always 保持着色)。然后,添加您想要的适用于每个字段的任何布尔表达式很简单。例如,这将打印作者电子邮件不是来自 fugly.com 的所有条目,并且提交日期是星期日:

    git log --color=always -z | awk -v RS=\\0 '!/Author:.*fugly.com>/ && /Date:.* Sun /'
    

    另一个好处是你可以在 git 日志中添加任何格式选项或修订范围,它仍然有效。

    最后一件事,如果要分页,请使用“less -r”来保留颜色。

    编辑:更改为在 awk 中使用 -v 以使其更简单。

    【讨论】:

    • 使用 perl:git log -z . |perl -ln0e 'print unless /regex/'
    【解决方案5】:

    生成所有提交的列表,减去那些日志消息包含违规模式的提交,然后将结果提供给git log,并提供您想要的选项。在最后阶段,git log 的几个选项很方便:

    --stdin
    除了命令行中列出的 commit 之外,从标准输入中读取它们。

    --no-walk
    只显示给定的转速,但不遍历它们的祖先。

    您可以使用单个管道和流程替换来做到这一点。

    #! /bin/bash
    
    if (( $# < 1 )); then
      echo >&2 "Usage: $0 pattern [<since>..<until>]"
      exit 1
    fi
    
    pattern=$1
    shift
    
    git log --format=%H $@ |
      grep -v -f <(git log --format=%H "--grep=$pattern" $@) |
      git log --pretty --stat --stdin --no-walk
    

    如果您不想使用 bash,可以使用 Perl。

    #! /usr/bin/env perl
    
    use strict;
    use warnings;
    no warnings "exec";
    
    sub usage { "Usage: $0 pattern\n" }
    
    sub commits_to_omit {
      my($pattern) = @_;
    
      open my $fh, "-|", "git", "log", "--grep=$pattern", "--format=%H", @ARGV
        or die "$0: exec: $!";
      my %omit = map +($_ => 1), <$fh>;
      %omit;
    }
    
    die usage unless @ARGV >= 1;
    my $pattern = shift;
    
    my %omit = commits_to_omit $pattern;
    
    open my $all, "-|", "git", "log", "--format=%H", @ARGV
      or die "$0: exec: $!";
    
    open my $out, "|-", "git", "log", "--pretty", "--stat", "--stdin", "--no-walk"
      or die "$0: exec: $!";
    
    while (<$all>) {
      print $out $_ unless $omit{$_};
    }
    

    假设上述之一在您的 PATH 中为 git-log-vgrep 并且具有表单的历史记录

    $ git lola
    * b0f2a28 (tmp, feature1) D
    * 68f87b0 C
    * d311c65 B
    * a092126 A
    | * 83052e6 (HEAD, origin/master, master) Z
    | * 90c3d28 是
    | * 4165a42 X
    | * 37844cb 瓦
    |/
    * f8ba9ea V

    我们可以说

    $ git log-vgrep X

    得到 Z、Y、W 和 V。

    你也可以登录其他分支,所以

    $ git log-vgrep A tmp

    给出 D、C、B 和 V;和

    $ git log-vgrep C tmp~2..tmp

    只产生 D。

    上述实现的一个限制是,如果您使用匹配所有提交的模式,例如.^,那么您将获得 HEAD。这就是git log 的工作原理:

    $ git log --stdin --no-walk --pretty=oneline /null
    83052e62f0dc1c6ddfc1aff3463504a4bf23e3c4 Z

    【讨论】:

      【解决方案6】:

      据我所知,这不可能直接使用单个命令行进行;您必须执行 Justin Lilly 建议的操作,然后在生成的哈希列表上运行“git log”,例如,

      git log --format="%h" | grep -v `git log -1 --grep="bumped to version" --format="%h"` > good-hashes
      for h in `cat good-hashes`; do
          PAGER=cat git log -1 --pretty --stat $h
      done
      

      应该可以解决问题。

      【讨论】:

      • 那太糟糕了。我希望有一些我错过的选项或者我应该升级到的新版本。 ebneter:我尝试了您的解决方案,但对我不起作用。
      • 嗯。为我工作,虽然我在过滤不同的字符串,当然。我很好奇什么不起作用?
      【解决方案7】:
      git log --pretty --stat | grep -v "bumped to version"
      

      【讨论】:

      • 这行不通,因为 --pretty --stat 每次提交都会产生多行。
      【解决方案8】:

      获取包含您的结果的所有提交的列表,然后过滤掉它们的哈希值。

      git log --format=oneline | grep -v `git log --grep="bumped to version" --format="%h"`
      

      【讨论】:

        猜你喜欢
        • 2018-08-08
        • 1970-01-01
        • 1970-01-01
        • 2012-12-23
        • 2022-11-15
        • 2019-12-28
        • 1970-01-01
        • 2019-03-14
        • 1970-01-01
        相关资源
        最近更新 更多