정규 표현식을 기반으로 diff / patch의 관련 덩어리 만 표시


20

git log -G<regex> -p지정된 패턴과 일치하는 변경 사항에 대해 코드베이스 기록을 검색하는 훌륭한 도구입니다. 그러나 주로 관련이없는 덩어리가있는 바다의 diff / patch 출력에서 ​​해당 덩어리를 찾는 것은 압도적 일 수 있습니다.

물론 git log원래의 문자열 / 정규식 에 대한 출력을 검색 할 수는 있지만 관련이없는 많은 변경 사항의 시각적 소음과 방해를 줄이기 위해 거의하지 않습니다.

에 대해 읽으면 git log, --pickaxe-all이것이 내가 원하는 것과 정확히 반대 인 것을 알 수 있습니다. 출력을 전체 변경 세트로 넓히고 출력을 특정 덩어리로 제한하고 싶습니다.

본질적으로, diff / patch를 개별 덩어리로 "지능적으로"구문 분석 한 다음 각 덩어리에 대해 검색을 수행하고 (변경된 행만 대상으로 함) 일치하지 않는 덩어리를 버리고 출력하는 방법을 찾고 있습니다. 그렇습니다.

내가 설명한 것과 같은 도구가 있습니까? 일치 / 영향을받는 덩어리를 얻는 더 나은 접근 방법이 있습니까?

내가 한 초기 연구 ...

  • grepdiff / patch 출력 이 가능 하고 컨텍스트 옵션 값을 동적 (예 : 라인 수 대신 정규 표현식을 통해)으로 설정하면 충분할 수 있습니다. 그러나 grep그런 식으로 정확하게 구축되지는 않았습니다 (필요로 그 기능을 요청하지도 않습니다).

  • patchutils 제품군을 찾았습니다. 처음에는 내 요구에 맞는 것처럼 들렸습니다. 그러나 해당 man페이지를 읽은 후에 는 도구가 정규 표현식을 기반으로 일치하는 덩어리를 처리하지 않는 것으로 보입니다. (그러나 그들은 덩어리의 목록을 수락 할 수 있습니다 ...)

  • 마지막으로 patch의 파싱을 잘 처리하는 것처럼 보이는 splitpatch.rb가 나타 났지만 ,을 통해 패치를 읽고 stdin, 원하는 덩어리를 일치시킨 다음 덩어리를 출력하려면 크게 보강해야합니다 .


1
정확하게 당신이 요구 한 것은 아니지만 git log -Gfoo | less + / foo
James Youngman

답변:


7

여기 /programming//a/35434714/5305907 은 당신이 찾고있는 것을 수행하는 방법에 대해 설명합니다. 효과적으로:

git diff -U1 | grepdiff 'console' --output-matching=hunk

주어진 문자열 "console"과 일치하는 덩어리 만 표시합니다.


감사. grepdiff기본적으로 내가 원하는 것입니다. 나는 그 덩어리 일치 옵션을 놓 쳤어 야합니다! 그러나 ... git commit info는에 의해 제거 grepdiff되므로 관련 덩어리를 찾으면 diff 헤더의 객체 / blo sha에서 commit sha를 작성해야합니다. ( stackoverflow.com/a/223890/2284440 참조 )git find-object SHA --reverse | head -1 | cut -c 1-7 | { read sha ; git log -1 $sha; }
wrksprfct

또한 허용되는 인수 측면에서 더 많은 골랭 버전의 golang 버전이grepdiff 있습니다. 일치하는 덩어리가 diff의 마지막 덩어리 인 경우 다음 커밋의 git commit 헤더가 잘못 포함되어 있습니다.
wrksprfct

0

정확히 당신이 요구하는 것이 아니라, 덩어리를 뚫는 방법은 대화 형 추가 모드입니다. 관심있는 패치 후에 커밋을 확인해야합니다.

git checkout COMMIT_ID

그런 다음 VCS에서 한 단계 더 돌아가지만 작업 디렉토리는 아닙니다.

git reset --soft HEAD^

(이 시점에서 인덱스와 작업 디렉토리의 차이는 관심있는 패치에 해당합니다.)

이제 실행할 수 있습니다 git add -p. 그러면 /옵션 이있는 대화식 세션이 시작되어 일부 라인이 정규식과 일치하는 덩어리를 찾을 수 있습니다. 패치를 부분적으로 처리하려는 경우 (예 : 부분 체리 픽 준비) 특히 유용합니다.

불행히도, 현재 /명령은 add -p하나의 파일 내에서만 작동하므로 관련이없는 여러 파일을 건너 뛰어야 할 수도 있습니다.


0

@nagu의 위의 답변과 다른 링크 된 답변을 바탕으로 git log -G관련 덩어리 만 표시 할 수있었습니다 .

  1. 먼저 다음 내용으로 $ PATH 어딘가에 스크립트를 작성하십시오.

    #!/bin/bash
    
    # pickaxe-diff : external diff driver for Git.
    #                To be used with the pickaxe options (git [log|show|diff[.*] [-S|-G])
    #                to only show hunks containing the searched string/regex.
    
    path=$1
    old_file=$2
    old_hex=$3
    old_mode=$4
    new_file=$5
    new_hex=$6
    new_mode=$7
    
    filtered_diff=$(diff -u -p $old_file $new_file | \
                    grepdiff "$GREPDIFF_REGEX" --output-matching=hunk | \
                    grep -v -e '+++ ' -e '--- ')
    
    a_path="a/$path"
    b_path="b/$path"
    
    echo "diff --git $a_path $b_path"
    echo "index $old_hex..$new_hex $old_mode"
    echo "--- $a_path"
    echo "+++ $b_path"
    echo "$filtered_diff"
  2. git log -GGit에 전화 하여 pickaxe-diff스크립트를 외부 diff 드라이버로 사용하도록 지시하십시오 .

    export GREPDIFF_REGEX=<string>; 
    GIT_EXTERNAL_DIFF=pickaxe-diff git log -p --ext-diff -G $GREPDIFF_REGEX

    이것은 pickaxe-diff 스크립트를 사용하여 diff를 생성하기 때문에 나머지 git log출력 (커밋 해시, 메시지 등)은 그대로 유지됩니다.

경고
Git pickaxe가 작동하는 방식 은 덩어리가 주어진 문자열 / 정규식을 변경하는 파일 로 출력을 제한하는 것 입니다. 즉, 이러한 파일의 다른 덩어리에도 검색 문자열 / 정규식이 포함되어 있지만 변경하지 않으면 위의 스크립트와 함께 계속 표시됩니다. 이것은 grepdiff의 한계입니다. patchutils 프로젝트에는 grepdiff에 --only-matching플래그를 추가하기위한 열린 풀 요청 이 있으며, 이러한 덩어리를 올바르게 필터링하는 데 필요한 기능을 제공합니다.


이 요점 에서 내 솔루션을 작성 했습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.