정규식과 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

파일에 저장된 샘플 커밋 로그의 경우 gitlogGNU grep명령은 다음을 추출합니다.

% < 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일치가 시작되는 위치를 제한 하는 데 사용할 수 있지만 GNU가 Perl처럼 일치 위치를 수정하는 플래그를 갖지 -z않는 한 이러한 일이 발생하지 않습니다 .grep^

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

이것은 GNU 플래그( 전체 입력을 받음) 의 덜 실험적인 버전 -0777으로 , 모든 곳에서 줄바꿈을 일치시키고 줄바꿈을 건너뛰는 정규식 플래그 입니다. 그러나 정규식은 각 커밋에 대해 전체 로그를 여러 번 검색해야 하고 필요한 버전 번호를 찾지 못할 수 있으므로 이는 매우 비효율적일 수 있습니다. 또는 버전 정보를 이전 커밋 라인 일치에만 제한하는 것이 없기 때문에 커밋을 여러 번 일치시킬 수 있습니다.grep -z-0777ms^.

또 다른 방법은 마지막 커밋을 기억하고 버전 번호를 찾을 때 해당 값을 사용하는 것입니다. 이를 통해 한 줄씩 구문 분석할 수 있습니다.

% < 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

괜찮아요, 제가 직접 해결책을 찾았어요.

알고 보니 중간쯤 왔지만 몇 가지 세부 사항이 누락되었습니다.

~처럼스택 오버플로에 대한 이 답변예상대로 작동 하려면 몇 가지 추가 매개변수를 전달해야 한다는 점을 설명하고 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

다음과 같이 "커밋" 텍스트를 제거할 수 있습니다.

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

관련 정보