使用正则表达式和 grep/perl 过滤 pom.xml 的 git 日志

使用正则表达式和 grep/perl 过滤 pom.xml 的 git 日志

我想pom.xml使用正则表达式过滤文件日志的内容。

我创建它于正则表达式它使用 PCRE 工作;这是我的正则表达式:

commit \K[a-z0-9]*(?=[\s\S]*\+.*<version>1.2.0)

然后我尝试使用以下命令运行:

git log --full-history -p pom.xml | grep -P "commit \K[a-z0-9]*(?=[\s\S]*\+.*<version>1.2.0)"

git log --full-history -p pom.xml | perl -nle 'print \$1 if /commit \K[a-z0-9]*(?=[\s\S]*\+.*<version>1.2.0)/'

但它们都不起作用(似乎没有任何匹配)。

我肯定错过了一些东西,但我不知道是什么。

编辑:

为了澄清这一点,这是一个例子git log

commit a1357f4e1cb2c34aa1a1357f4e1cb2c34aa1471f
Author: Author <[email protected]>
Date:   Wed Mar 30 15:04:29 2022 +0100
 
    commit message
 
diff --git a/pom.xml b/pom.xml
index 93df07e..5f82fd2 100755
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.organization.project</groupId>
        <artifactId>ProjectName</artifactId>
-       <version>1.1.1</version>
+       <version>1.2.0</version>
        <name>ProjectName</name>
        <description>Description of project</description>

我想选择version更改为某个值的提交的哈希值(1.2.0在我编写的正则表达式中)。

显然,这是在某个存储库上完成的所有提交的日志,也可能有多个提交。

在此输入上使用上述正则表达式应输出提交哈希:

a1357f4e1cb2c34aa1a1357f4e1cb2c34aa1471f

这就是使用 regexr 实际发生的情况。

答案1

对于保存到文件中的示例提交日志gitlog,GNUgrep命令会提取

% < gitlog ggrep -Pzo 'commit \K[a-z0-9]*(?=[\s\S]*\+.*<version>1.2.0)'
a1357f4e1cb2c34aa1a1357f4e1cb2c34aa1471fmessage%
% < gitlog ggrep -Pzo 'commit \K[a-z0-9]*(?=[\s\S]*\+.*<version>1.2.0)' | od -c
0000000    a   1   3   5   7   f   4   e   1   c   b   2   c   3   4   a
0000020    a   1   a   1   3   5   7   f   4   e   1   c   b   2   c   3
0000040    4   a   a   1   4   7   1   f  \0   m   e   s   s   a   g   e
0000060   \0
0000061

考虑到误报,这可能并不理想。此外,PCRE 标志的文档-P提到了一些关于进行实验的内容-z。使用基于行的正则表达式,我们可以用来^commit限制匹配开始的位置,但-z会阻止这种情况发生,除非 GNUgrep有一个标志来修改^匹配的位置,就像 Perl 那样:

% < gitlog perl -0777 -nE 'say $1 if m/^commit (\S+).*<version>1.2.0/ms'
a1357f4e1cb2c34aa1a1357f4e1cb2c34aa1471f

-0777是 GNUgrep -z标志的一个实验性较低的版本(-0777吸收整个输入),正ms则表达式标志可以^在任何地方匹配换行符并.跳过换行符。但是,这可能效率极低,因为正则表达式可能必须为每次提交多次搜索整个日志,并且可能找不到所需的版本号。或者,它可以多次匹配提交,因为没有任何内容限制版本信息仅与之前的提交行匹配。

另一种方法是记住最后一次提交,并在找到版本号时使用该值。这允许逐行解析:

% < gitlog perl -nle 'if (m/^commit (\S+)/) {$commit=$1} if(m/<version>1.2.0/) {print $commit}'
a1357f4e1cb2c34aa1a1357f4e1cb2c34aa1471f

{print $commit;exit}如果您不关心输入的其余部分(可能很多),这可能会在找到匹配版本时停止搜索。

% < gitlog perl -nle 'if (m/^commit (\S+)/) {$commit=$1} if(m/<version>1.2.0/) {print $commit;exit}'
a1357f4e1cb2c34aa1a1357f4e1cb2c34aa1471f

为了获得更快的速度,可以将其编写为awk,我通常只有在用 Perl 编写后才能弄清楚:

% < gitlog awk '/^commit/{c=$2};/<version>1.2.0/{print c;exit}'
a1357f4e1cb2c34aa1a1357f4e1cb2c34aa1471f

理想情况下,您的测试输入(或多个输入)应该执行许多不同的可能性:目标之前和之后的多个提交记录、重复记录等,特别是如果此代码要以任何形式的无人值守方式使用,而无需人工干预。健全性检查结果:

% < gitlog
blah blah blah

commit a1357f4e1cb2c34aa1a1357f4e1cb2c34aa1471f

    commit eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee

-       <version>1.1.1</version>
+       <version>1.2.0</version>

commit ffffffffffffffffffffffffffffffffffffffff
+       <version>1.2.0</version>

答案2

没关系,我自己找到了解决方案。

事实证明我已经完成了一半,但我遗漏了一些细节。

作为Stack Overflow 上的这个答案解释说,有必要传递一些其他参数才能grep使其按预期工作;此外,使用单引号而不是双引号。

因此,第一个命令变为:

git log --full-history -p pom.xml | grep -Pzo 'commit \K[a-z0-9]*(?=[\s\S]*\+.*<version>1.2.0)'

答案3

使用(以前称为 Perl_6)

<version>1.2.0如果在文本后面找到以下代码,则从 gitlog 提交中提取第一行:

raku -e 'put $_.split("\n")[0] if m/ \<version\>1\.2\.0 / given slurp();' 

#OR

raku -e 'put lines[0] if m/ \<version\>1\.2\.0 /;'   

返回:

commit a1357f4e1cb2c34aa1a1357f4e1cb2c34aa1471f

您可以按如下方式删除“commit”文本:

raku -e 'put $_.split("\n")[0].subst("commit ") if m/\<version\>1\.2\.0/ given slurp();' 

返回:

a1357f4e1cb2c34aa1a1357f4e1cb2c34aa1471f

在 Raku 中,正则表达式的转义规则非常简单:只需反斜杠每个非<alnum>字符即可将其理解为文字(即假设non-<alnum>s 具有特殊含义 - 就像.代表任何字符的点)。或者引用您正在搜索的文本,即m/ "<version>1.2.0" /

raku -e 'put .split("\n")[0].subst("commit ") if m/"<version>1.2.0"/ given slurp();' 

#OR

raku -e 'put .[0].subst("commit ") if m/"<version>1.2.0"/ given lines();'     

返回:

a1357f4e1cb2c34aa1a1357f4e1cb2c34aa1471f

https://raku.org

相关内容