首页 > 解决方案 > git log grep里面的内容变化

问题描述

我有一个包含 100K+ 提交的仓库。很少有提交(≈500)可能在提交消息中有一个单词 PROJECT_BOAT_COMMIT 文本。

git commit -m "PROJECT_BOAT_COMMIT: This is project boat's first commit";

每个提交都针对多个文件(添加的行、删除的行、删除的文件、添加的文件等)。

作为任何提交的一部分(不特定于 PROJECT_BOAT_COMMIT),可能已经从任何文件中添加/删除了一个特定的关键字(比如 BOAT_TODO)。

git diff ./file1

+BOAT_TODO


git diff ./file2

-BOAT_TODO

我想要做

标签: git

解决方案


您可以使用以下命令执行此操作:

git log --grep=PROJECT_BOAT_COMMIT --format=%H | xargs -L1 sh -c 'git diff $0^ $0 | COMMIT="$0" perl -ne '\''if (/^[-+]{3} [ab]\/(.*)/) { printf "%s %s %d %d\n", $ENV{COMMIT}, $n, $x{"-"}, $x{"+"} if $n && $n ne $1; $n=$1;} $x{$1}++ if /^([-+]).*BOAT_TODO/; END{ printf "%s %s %d %d\n", $ENV{COMMIT}, $n, $x{"-"}, $x{"+"}; }'\'''

本质上,它在提交消息中使用 PROJECT_BOAT_COMMIT 迭代每个提交,打印哈希,然后调用git diff命令并过滤输出以查找引入文件名或包含添加或删除的“BOAT_TOOD”的行,并将输出打印在表格<commit> <filename> <removals> <additions>

那是一个命令,这就是您所要求的,尽管它不是特别漂亮。我已将其格式化为下面的 shell 脚本,以防更具吸引力。如果你更喜欢 Perl 以外的东西,你也可以使用不同的脚本语言,但是 Perl 在 Git 所在的所有系统上都可用,所以我选择了它以防你使用 Windows。如果您在文件名中使用空格或类似的东西,您可以调整它。

最后,如果你想避免一堆(虽然不是全部)没有添加或删除的行,你可以添加参数-G BOAT_TODO,这将限制 Git 只打印那些包含“BOAT_TODO”的提交。否则,它将打印包含“PROJECT_BOAT_COMMIT”的所有提交的数据,无论该提交是否包含“BOAT_TODO”的任何实例。

如果您正在寻找简单而优雅的东西,我很抱歉;Git 并没有提供一种简单而优雅的方式来做你想做的事,而脚本绝对是实现你目标的 Git 方式。

#!/bin/sh

git log --grep=PROJECT_BOAT_COMMIT --format=%H | \
    xargs -L1 sh -c '
    git diff $0^ $0 | \
    COMMIT="$0" perl -n -e '\''if (/^[-+]{3} [ab]\/(.*)/) {
        printf "%s %s %d %d\n", $ENV{COMMIT}, $n, $x{"-"}, $x{"+"} if $n && $n ne $1;
        $n=$1;
    }
    $x{$1}++ if /^([-+]).*BOAT_TODO/;
    END {
        printf "%s %s %d %d\n", $ENV{COMMIT}, $n, $x{"-"}, $x{"+"};
    }
'\'''

推荐阅读