파일에서 특정 줄에 대한 커밋 로그를 검색 하시겠습니까?


502

git 이 파일 의 특정 에 닿은 커밋에 대한 커밋 로그를 제공하는 방법이 있습니까?

처럼 git blame, 그러나 git blame특정 줄에 닿은 LAST 커밋을 보여줍니다.

파일의 어느 위치에 대한 커밋 목록이 아니라 특정 줄에 닿은 커밋 목록과 비슷한 로그를 얻고 싶습니다.


2
참조 : Git
Blame-

답변:


631

Git : 어느 커밋이 다양한 라인에 닿았는지 발견 하십시오 .


힘내 1.8.4 이후 , git log-L라인의 범위의 진화를 볼 수 있습니다.

예를 들어 git blame의 출력을 봅니다. 여기에 -L 150,+11"단지 라인을 보려면 150 + 11 150"를 의미한다 :

$ git blame -L 150,+11 -- git-web--browse.sh
a180055a git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:36 +0100 150)            die "The browser $browser is not
a180055a git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:36 +0100 151)    fi
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 152) fi
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 153) 
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 154) case "$browser" in
81f42f11 git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:38 +0100 155) firefox|iceweasel|seamonkey|iceape)
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 156)    # Check version because firefox < 2.0 do
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 157)    vers=$(expr "$($browser_path -version)" 
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 158)    NEWTAB='-new-tab'
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 159)    test "$vers" -lt 2 && NEWTAB=''
a0685a4f git-web--browse.sh (Dmitry Potapov   2008-02-09 23:22:22 -0800 160)    "$browser_path" $NEWTAB "$@" &

그리고 지금 155 행의 역사를 알고 싶습니다.

그런 다음을 사용하십시오 git log. 여기서는 -L 155,155:git-web--browse.sh"파일명에서 155 행에서 155 행까지의 진화를 추적"을 의미합니다 git-web--browse.sh.

$ git log --pretty=short -u -L 155,155:git-web--browse.sh
commit 81f42f11496b9117273939c98d270af273c8a463
Author: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>

    web--browse: support opera, seamonkey and elinks

diff --git a/git-web--browse.sh b/git-web--browse.sh
--- a/git-web--browse.sh
+++ b/git-web--browse.sh
@@ -143,1 +143,1 @@
-firefox|iceweasel)
+firefox|iceweasel|seamonkey|iceape)

commit a180055a47c6793eaaba6289f623cff32644215b
Author: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>

    web--browse: coding style

diff --git a/git-web--browse.sh b/git-web--browse.sh
--- a/git-web--browse.sh
+++ b/git-web--browse.sh
@@ -142,1 +142,1 @@
-    firefox|iceweasel)
+firefox|iceweasel)

commit 5884f1fe96b33d9666a78e660042b1e3e5f9f4d9
Author: Christian Couder <chriscool@tuxfamily.org>

    Rename 'git-help--browse.sh' to 'git-web--browse.sh'.

diff --git a/git-web--browse.sh b/git-web--browse.sh
--- /dev/null
+++ b/git-web--browse.sh
@@ -0,0 +127,1 @@
+    firefox|iceweasel)

2
'git log --topo-order --graph -u -L 155,155 : git-web--browse.sh'-치명적인 오류가 발생했습니다 : '잘못된 객체 이름 155,155'. 힘내 버전 : 1.8.3.2. 어떤 제안?
BairDev

12
Git 1.8.4 이상으로 업그레이드하십시오.
Matt McClure

4
"HEAD의 155 행 대신에"commitA의 155 행의 이력 "을 알고 싶다면 어떨까요? 간단히 사용할 수 있습니까 git log commitA-hash -L 155,155:file-name?
Ida

@Flimm, 나는 강한 선호도가 없습니다.
Matt McClure

파일이 이동되거나 이름이 변경된 경우를 제외하고는 잘 작동합니다.
Mike Ellery

66

pick-axe를 사용하여 커밋 세트를 얻을 수 있습니다.

git log -S'the line from your file' -- path/to/your/file.txt

그러면 해당 파일의 해당 텍스트에 영향을 미치는 모든 커밋이 제공됩니다. 파일 이름이 변경되면 --follow-parent를 추가 할 수 있습니다.

이러한 각 편집에서 커밋을 검사하려면 해당 결과를 git show로 파이프하십시오.

git log ... | xargs -n 1 git show

5
이것이 어떻게 도움이되는지 잘 모르겠습니다. 텍스트가 영향을받는 경우 해당 라인은 더 이상 동일하지 않으므로 곡괭이는 가장 최근의 변경 사항 만 표시합니다. 그런 다음으로 git log -S'the previous version of the line'끝나는 것처럼 정확하게해야합니다 git blame -L. 그리고 그것은 git blame주어진 장소뿐만 아니라 모든 곳에서 텍스트를 찾아야하기 때문에 보다 느립니다 .
Cascabel

거기에 정규 표현식을 사용하여 더 받아 들일 수 있습니다. 현재는 정교한 스크립팅없이 "패치를 탐색"할 수있는 방법이 없습니다. gitk가 향후 패치보기에서이 기능을 사용할 수 있기를 바랍니다.
Adam Dymitruk

3
왜 이것을 pick-axe 라고 합니까? :)
Ciprian Tomoiagă


14

가장 쉬운 방법은 vim-fugitive를 사용하는 것 입니다. vim에서 파일을 열고 사용하고자하는 라인을 V선택한 다음,

:Glog

이제 해당 행이 수정 된 파일의 모든 개정판을 사용 :cnext하고 :cprev볼 수 있습니다 . 언제라도 :GblameSha, 작성자 및 날짜 정보를 보려면 입력 하십시오.


13

@matt의 답변 단순화-

git blame -L14,15 -- <file_path>

여기서 당신은 선의 비난을받을 것 14 to 15입니다.

-Loption Range은 매개 변수로 기대 하기 때문에 ``옵션을 Blame사용하여 한 줄을 얻을 수 없습니다-L .

참고


10

나는 이것에 대해 내장 된 것이 없다고 생각합니다. 한 줄이 파일의 나머지 부분을 크게 변경하지 않고 여러 번 변경하는 경우가 드물기 때문에 까다로워서 줄 번호가 많이 바뀌는 경향이 있습니다.

라인이 항상 가지고있는 거 운이 충분히 당신이 경우 몇 가지 이름이 변경되지 않습니다 변수에 예를 들어 할당 식별 특성을, 당신의 정규식 검색을 사용할 수 있습니다 git blame -L. 예를 들면 다음과 같습니다.

git blame -L '/variable_name *= */',+1

그러나 이것은 정규 표현식과 일치 하는 첫 번째 항목 만 찾기 때문에 줄을 일치시키는 좋은 방법이 없다면 너무 도움이되지 않습니다.

당신은 뭔가를 해킹 할 수 있다고 생각합니다. 지금 코드를 작성할 시간이 없지만 ...이 줄을 따라 뭔가. 를 실행하십시오 git blame -n -L $n,$n $file. 첫 번째 필드는 터치 한 이전 커밋이고 두 번째 필드는 변경 될 수 있으므로 해당 커밋 의 줄 번호입니다 . 파일을 가져 와서 실행하십시오 git blame -n $n,$n $commit^ $file. 즉, 파일이 마지막으로 변경되기 전에 커밋에서 시작하는 것과 동일한 것입니다.

(라인을 변경 한 마지막 커밋이 병합 커밋 인 경우에는 실패합니다. 라인이 병합 충돌 해결의 일부로 변경된 경우에 발생할 수있는 기본 방법입니다.)

편집 : 나는 오늘 2011 년 3 월 부터이 메일 링리스트 게시물 에서 이것을 언급했으며 tig이를 git gui수행하는 데 도움이되는 기능이 있습니다. git 자체에 대해 기능이 고려되었지만 완료되지 않은 것처럼 보입니다.


6

이 호출 git blame에 대한 모든 쇼 라인에 의미있는 수정 $LINE파일 $FILE:

git log --format=format:%H $FILE | xargs -L 1 git blame $FILE -L $LINE,$LINE

평소와 같이 비난은 각 줄의 시작 부분에 개정 번호를 표시합니다. 당신은 추가 할 수 있습니다

| sort | uniq -c

이 줄을 바꾼 커밋 목록과 같은 집계 결과를 얻으려면. (코드 만 이동 한 경우 줄의 다른 내용에 대해 동일한 커밋 ID가 두 번 표시 될 수 있습니다. 더 자세한 분석 git blame을 위해서는 인접한 커밋 에 대한 결과를 지연 비교해야합니다 . )


다시 말하지만 이것은 해당 라인의 이전 위치를 추적하지 않기 때문에 작동하지 않는다고 생각합니다. 라인 2 커밋 전에 추가 된 경우 그래서, 당신은 다른 라인에서 찾고있을 것이다
빅 Seedoubleyew

6

다음은 git alias를 정의하는 솔루션이므로 다음과 같이 사용할 수 있습니다.

git rblame -M -n -L '/REGEX/,+1' FILE

출력 예 :

00000000 18 (Not Committed Yet 2013-08-19 13:04:52 +0000 728) fooREGEXbar
15227b97 18 (User1 2013-07-11 18:51:26 +0000 728) fooREGEX
1748695d 23 (User2 2013-03-19 21:09:09 +0000 741) REGEXbar

.gitconfig 에서 별칭을 정의 하거나 다음 명령을 간단히 실행할 수 있습니다

git config alias.rblame !sh -c 'while line=$(git blame "$@" $commit 2>/dev/null); do commit=${line:0:8}^; [ 00000000^ == $commit ] && commit=$(git rev-parse HEAD); echo $line; done' dumb_param

이것은 추악한 one-liner이므로, 난독 화 처리 된 동등한 bash 함수가 있습니다.

git-rblame () {
    local commit line
    while line=$(git blame "$@" $commit 2>/dev/null); do
        commit="${line:0:8}^"
        if [ "00000000^" == "$commit" ]; then
            commit=$(git rev-parse HEAD)
        fi
        echo $line
    done
}

곡괭이 솔루션 ( git log --pickaxe-regex -S'REGEX ' )은 정규 표현식을 포함하는 줄의 다른 변경 사항이 아니라 줄 추가 / 삭제 만 제공합니다.

이 솔루션의 한계는 git blame 이 첫 번째 REGEX 일치 만 반환하므로 여러 일치가 존재하면 재귀가 다른 줄을 따라 "점프"할 수 있다는 것입니다. 이러한 "점프"를 발견하기 위해 전체 히스토리 출력을 확인한 다음 기생충 선을 무시하도록 REGEX를 수정하십시오.

마지막으로, 각 커밋마다 git show 를 실행 하여 전체 diff를 얻는 대체 버전이 있습니다 .

git config alias.rblameshow !sh -c 'while line=$(git blame "$@" $commit 2>/dev/null); do commit=${line:0:8}^; [ 00000000^ == $commit ] && commit=$(git rev-parse HEAD); git show $commit; done' dumb_param

2

git blame 명령에서 각 커밋의 요약을 검색하고 추가하기 위해 명령 git blamegit log명령을 혼합 할 수 있습니다 . 다음 bash + awk 스크립트와 같은 것. 커밋 요약을 코드 주석 인라인으로 추가합니다.

git blame FILE_NAME | awk -F" " \
'{
   commit = substr($0, 0, 8);
   if (!a[commit]) {
     query = "git log --oneline -n 1 " commit " --";
     (query | getline a[commit]);
   }
   print $0 "  // " substr(a[commit], 9);
 }'

한 줄로 :

git blame FILE_NAME | awk -F" " '{ commit = substr($0, 0, 8); if (!a[commit]) { query = "git log --oneline -n 1 " commit " --"; (query | getline a[commit]); } print $0 "  // " substr(a[commit], 9); }'

2

제 경우에는 줄 번호가 시간이 지남에 따라 많이 바뀌 었습니다. 또한 "git blame -L"의 정규 표현식을 지원하지 않는 git 1.8.3에있었습니다. (RHEL7에는 여전히 1.8.3이 있습니다)

myfile=haproxy.cfg
git rev-list HEAD -- $myfile | while read i
do
    git diff -U0 ${i}^ $i $myfile | sed "s/^/$i /"
done | grep "<sometext>"

짧막 한 농담:

myfile=<myfile> ; git rev-list HEAD -- $myfile | while read i; do     git diff -U0 ${i}^ $i $myfile | sed "s/^/$i /"; done | grep "<sometext>"

이것은 물론 스크립트 나 함수로 만들 수 있습니다.

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