Git 히스토리에서 커밋 된 코드를 grep (검색)하는 방법


1433

과거에 파일이나 파일에서 일부 코드를 삭제했습니다. 커밋 메시지가 아닌 컨텐츠를 grep 할 수 있습니까?

매우 나쁜 해결책은 로그를 grep하는 것입니다.

git log -p | grep <pattern>

그러나 커밋 해시를 즉시 반환하지는 않습니다. 나는 git grep아무 소용이 없습니다.


2
Junio ​​C Hamano (git 관리자)의이 블로그 게시물은 여러분에게 흥미로울 것입니다. * Linus의 궁극적 인 콘텐츠 추적 도구 (pickaxe 검색 즉 git log -S, 비난에 대해) * [ "git log --grep"와 함께 재미] [2] (커밋 메시지 검색) ) * [ "git grep"으로 재미있게] [3] [2] : gitster.livejournal.com/30195.html [3] : gitster.livejournal.com/27674.html
Jakub Narębski


가능한 중복 복제에 대한 대답은 실제로 작동합니다 : stackoverflow.com/a/1340245/492
CAD

이와 문제는 변화에 대한 컨텍스트를 제공하지 않는다는 것입니다 .. 즉, 사람 /시
소닉 소울

답변:


1889

커밋 내용 (즉, 커밋 메시지 등이 아닌 실제 소스 행) 을 검색하려면 다음을 수행해야합니다.

git grep <regexp> $(git rev-list --all)

git rev-list --all | xargs git grep <expression> "인수 목록이 너무 깁니다"오류가 발생하면 작동합니다.

일부 하위 트리로 검색을 제한하려면 (예를 들어, "lib 디렉토리 / 폴더의 유틸리티"), 당신은 그에게 전달해야합니다 rev-list하위 명령 및 grep뿐만 아니라 :

git grep <regexp> $(git rev-list --all -- lib/util) -- lib/util

에 대한 커밋 텍스트가 모두 표시됩니다 regexp.

두 명령 모두에 경로를 전달하는 이유는 rev-list모든 변경 사항이 lib/util발생한 수정본 목록을 반환 하지만 grep검색 만하 도록 전달해야하기 때문입니다 lib/util.

다음 시나리오를 상상해보십시오. 반환 된 동일한 개정판에 포함 된 다른 파일 grep에서도 동일하게 찾을 수 있습니다 (해당 개정판에서 해당 파일에 대한 변경 사항이 없더라도).<regexp>rev-list

소스를 검색하는 다른 유용한 방법은 다음과 같습니다.

정규식 regexp와 일치하는 텍스트에 대한 작업 트리 검색 :

git grep <regexp>

정규식 regexp1 또는 regexp2와 일치하는 텍스트 행에 대한 작업 트리를 검색하십시오.

git grep -e <regexp1> [--or] -e <regexp2>

정규식 regexp1 및 regexp2와 일치하는 텍스트 행에 대한 작업 트리를 검색하고 파일 경로 만보고하십시오.

git grep -l -e <regexp1> --and -e <regexp2>

정규식 regexp1과 일치하는 텍스트 행과 정규식 regexp2와 일치하는 텍스트 행이있는 파일에 대한 작업 트리를 검색하십시오.

git grep -l --all-match -e <regexp1> -e <regexp2>

변경된 텍스트 일치 패턴 행에 대한 작업 트리 검색 :

git diff --unified=0 | grep <pattern>

정규식 regexp와 일치하는 텍스트에 대한 모든 개정판을 검색하십시오.

git grep <regexp> $(git rev-list --all)

정규식 regexp와 일치하는 텍스트에 대해 rev1과 rev2 사이의 모든 개정판을 검색하십시오.

git grep <regexp> $(git rev-list <rev1>..<rev2>)

61
고마워요, 잘 작동합니다! "$ (git rev-list --all)"이 필요하고 지점의 전체 히스토리에서 검색을 지정하는 편리한 스위치가없는 것은 슬픈 일입니다.
Ortwin Gentz

3
우수한. +1. GitBook은 몇 가지 세부 정보 ( book.git-scm.com/4_finding_with_git_grep.html )를 추가 하고 Junio ​​C Hamano
VonC

18
불행히도, 나는 이것을 msysgit-1.7.4로 갈 수 없습니다. 그것은 나에게 말한다 sh.exe": /bin/git: Bad file number. VonC의 답변은 msysgit에서도 작동합니다.
eckes

4
rev-list로 git grep history를 호출 할 때 "트리를 읽을 수 없습니다"오류가 발생하면 정리해야합니다. 시도 git gc또는 체크 아웃 : stackoverflow.com/questions/1507463/…
Anthony Panozzo

8
예, 이것은 Windows에서도 실패하는 것 같습니다.
mlissner 2014

552

pickaxe ( -S) 옵션을 사용해야합니다 git log.

검색하려면 Foo:

git log -SFoo -- path_containing_change
git log -SFoo --since=2009.1.1 --until=2010.1.1 -- path_containing_change

자세한 내용은 Git history (Git 기록)를 참조하십시오 .


Jakub Narębski 는 다음과 같이 언급했습니다.

  • 이것은 의 인스턴스를 소개하거나 제거하는 차이점을 찾습니다<string> . 일반적으로 " 'Foo'로 라인을 추가하거나 제거한 개정"을 의미합니다.

  • --pickaxe-regex옵션을 사용하면 문자열을 검색하는 대신 확장 POSIX 정규식을 사용할 수 있습니다. 예 (에서 git log) :git log -S"frotz\(nitfol" --pickaxe-regex


Rob이 언급 한 것처럼 이 검색은 대소 문자를 구분합니다. 대소 문자를 구분하지 않는 검색 방법에 대한 후속 질문 을 열었 습니다 .


3
고마워, 나는이 옵션을 몰랐다. 커밋 메시지에 관심이 있다면 이것이 최선의 해결책이며, 순수한 라인 매칭의 전통적인 UNIX grep 동작이 필요한 경우 Jeet의 솔루션이 가장 적합합니다.
Ortwin Gentz

@ Ortwin : 동의했습니다 (그리고 선택한 솔루션을 upvoted했습니다). git log귀하의 질문에 조금 나를 혼동했다)
VonC

12
-p플래그 와 결합 하여 diff도 출력하십시오.
샌더

git log -S를 사용하여 특정 패턴과 일치하는 모든 디렉토리를 제외시키는 방법이 있습니까?
BakaKuna

3
@Anentropic 당신은 --branches --all모든 repo를 검색 하는 옵션 이 필요합니다 .
VonC

249

가장 좋아하는 방법은 git log-G옵션을 사용하는 것입니다 (버전 1.7.4에 추가됨).

-G<regex>
       Look for differences whose added or removed line matches the given <regex>.

커밋과 일치하는지 -G-S옵션이 결정 하는 방식에는 미묘한 차이가 있습니다.

  • -S옵션은 기본적으로 커밋 전후에 파일에서 검색이 일치하는 횟수를 계산합니다. 이전 및 이후 개수가 다른 경우 커밋이 로그에 표시됩니다. 예를 들어, 검색과 일치하는 행이 이동 된 커밋은 표시되지 않습니다.
  • -G옵션을 사용하면 검색이 추가, 제거 또는 변경된 행과 일치하면 커밋이 로그에 표시됩니다.

이 커밋을 예로 들어 보겠습니다.

diff --git a/test b/test
index dddc242..60a8ba6 100644
--- a/test
+++ b/test
@@ -1 +1 @@
-hello hello
+hello goodbye hello

파일에 "hello"가 나타나는 횟수는이 커밋 전후에 동일하기 때문에를 사용하여 일치하지 않습니다 -Shello. 그러나 일치하는 행이 변경 hello되었으므로 커밋은을 사용하여 표시됩니다 -Ghello.


2
자식 로그 출력에 일치하는 변경 컨텍스트를 표시하는 방법이 있습니까?
Thilo-Alexander Ginkel

13
@ Thilo-AlexanderGinkel-보통 -p커밋마다 diff를 표시하는 옵션을 추가합니다 . 그런 다음 내 호출기에서 로그가 열리면 원하는 것을 검색합니다. 호출기 인 경우 less당신은 git log -Ghello -p, 당신은 입력 할 수 /hello눌러 Enter및 사용 nN"안녕하세요"의 이전 / 다음 항목을 찾을 수 있습니다.
Tyler Holien

-GRegex 에서 흥미로운 문제를 발견했습니다 . 명령 줄에 UTF-8이 사용되고보고있는 파일이 ISO-Latin (8 비트) 인코딩을 사용 .*하면 실패합니다. 예를 들어, 나는 변경 Vierter Entwurf->을 가지고 있고 일치 Fünfter Entwurf하는 것을 'V.*ter Entwurf'생성하지만 'F.*ter Entwurf'그렇지 않습니다.
U. Windl

51

코드 변경 사항을 탐색하려면 (전체 기록에서 주어진 단어로 실제로 변경된 내용을 참조하십시오) patch모드 로 이동하십시오 .

git log -p
# Hit '/' for search mode.
# Type in the word you are searching.
# If the first search is not relevant, hit 'n' for next (like in Vim ;) )

11
Accepeted 솔루션은 git log -S 나에게 효과적이지 않습니다. 이거 했어요!
rodvlopes

29

git log 일치하는 항목이 많고 가장 최근 (관련) 변경 사항을 먼저보고자하는 경우 모든 브랜치에서보다 효과적인 텍스트 검색 방법이 될 수 있습니다.

git log -p --all -S 'search string'
git log -p --all -G 'match regular expression'

이 로그 명령은 주어진 검색 문자열 / 정규식 (일반적으로)을 먼저 추가하거나 제거하는 커밋을 나열합니다. 이 -p옵션을 사용하면 패턴이 추가되거나 제거 된 위치에 관련 diff가 표시되므로 컨텍스트에서 볼 수 있습니다.

찾고있는 텍스트를 추가하는 관련 커밋 (예 : 8beeff00d)을 찾았 으면 커밋이 포함 된 분기를 찾습니다.

git branch -a --contains 8beeff00d

안녕하세요,이 라인은 전혀 작동하지 않는 것 같습니다. 내 명령은> git log -p --all -S 'public string DOB {get; 세트; } = 문자열. 빈; ' 그리고 그것을 실행할 때마다> 치명적 : 모호한 인수 'string': 알 수없는 개정 또는 작업 트리에없는 경로. > '-'를 사용하여 경로를 수정본에서 분리하십시오.> 'git <command> [<revision> ...]-[<file> ...]'
user216652

@ user216652 어떤 이유로 ' 따옴표가 검색 문자열을 단일 인수로 그룹화하지 않습니다. 대신에 'public의 주장 -S이며 나머지는 별도의 주장으로 취급합니다. 어떤 환경에서 실행 중인지 잘 모르겠지만 문제 해결에 도움이되는 컨텍스트가 필요합니다. git 명령이 셸로 전송되는 방법에 대한 모든 컨텍스트와 함께 문제 해결에 도움이 필요한 경우 별도의 StackOverflow 질문을 여는 것이 좋습니다. 다른 명령을 통해 전송되는 것 같습니다. 여기의 의견은 이것을 알아낼 수있는 올바른 장소가 아닙니다.
Edward Anderson

26

Jeet의 답변을 가져 와서 Windows에 적용했습니다 ( 이 답변 덕분에 ).

FOR /F %x IN ('"git rev-list --all"') DO @git grep <regex> %x > out.txt

어떤 이유로 든이 정규 표현식을 삭제 한 실제 커밋은 명령의 출력에 나타나지 않고 명령보다 먼저 커밋되었습니다.


2
+ --no-pager
1-

2
또한 텍스트 파일에 추가하면 실제로 일치하는 텍스트를 표시하는 이점이 있습니다. ( >>results.txt윈도우 파이프에 정통하지 않은 파일을 사용하여 텍스트 파일에 추가 ...
cgp

1
그리고 나는 bash의 구문이 추악하다고 생각했다 :)
smido

23

모든 버전의 파일 에서 검색 :

git rev-list --all | xargs git grep <regexp>

주어진 파일 ( : XML 파일) 에서만 검색 하십시오.

git rev-list --all | xargs -I{} git grep <regexp> {} -- "*.xml"

결과 줄은 다음과 같아야합니다. 6988bec26b1503d45eb0b2e8a4364afb87dde7af : bla.xml : 찾은 줄의 텍스트 ...

그런 다음 다음을 사용하여 저자, 날짜 및 diff와 같은 자세한 정보를 얻을 수 있습니다 git show.

git show 6988bec26b1503d45eb0b2e8a4364afb87dde7af

11

간단하게하기 위해 GUI를 사용하는 것이 좋습니다 : gitk-The Git repository browser . 꽤 유연합니다

  1. 코드를 검색하려면

    여기에 이미지 설명을 입력하십시오
  2. 파일을 검색하려면

    여기에 이미지 설명을 입력하십시오
  3. 물론 정규 표현식도 지원합니다.

    여기에 이미지 설명을 입력하십시오

위 / 아래 화살표를 사용하여 결과를 탐색 할 수 있습니다.


6

소스 트리 에서이 작업을 수행하려는 다른 사람 은 UI에 직접 명령이 없습니다 (버전 1.6.21.0 기준). 그러나 터미널 창 (기본 도구 모음에서 사용 가능한 단추) 을 열고 복사 / 붙여 넣기 하여 허용 된 답변에 지정된 명령 을 사용할 수 있습니다.

참고 : 소스 트리의 검색 보기는 부분적으로 텍스트 검색을 수행 할 수 있습니다. Ctrl+ 3를 눌러 검색보기로 이동하거나 하단에서 사용 가능한 검색 탭을 클릭하십시오. 가장 오른쪽에서 검색 유형을 파일 변경으로 설정 한 다음 검색 할 문자열을 입력하십시오. 이 방법에는 위의 명령과 비교하여 다음과 같은 제한이 있습니다.

  1. 소스 트리 에는 변경된 파일 중 하나에 검색어가 포함 된 커밋 만 표시 됩니다. 검색 텍스트가 포함 된 정확한 파일을 찾는 것은 다시 수동 작업입니다.
  2. RegEx는 지원되지 않습니다.

4

내가 당신을 찾을 때마다 다음 명령 줄을 사용합니다.

git log -S "<words/phrases i am trying to find>" --all --oneline  --graph

설명:

  1. git log-내가 더 쓸 필요가 있습니다; 로그를 시간순으로 표시합니다.
  2. -S "<words/phrases i am trying to find>" -파일 (추가 / 수정 / 삭제)에 '<>'기호없이 찾으려고하는 단어 / 문구가있는 Git 커밋을 모두 보여줍니다.
  3. --all -모든 지점에서 시행하고 검색합니다.
  4. --oneline -Git 로그를 한 줄로 압축합니다.
  5. --graph -시간순으로 커밋 된 그래프를 생성합니다.

1
"내가 당신의 자리를 찾을 때마다 git을 사용할 필요가 있다고 생각합니다!"
Sebi

1
이것은 좋은 답변입니다!
Alf Eaton

@AlfEaton 내 기쁨!
surajs1n

2

Jeet의 답변 은 PowerShell에서 작동합니다.

git grep -n <regex> $(git rev-list --all)

다음은 모든 커밋에서을 포함하는 모든 파일을 표시합니다 password.

# Store intermediate result
$result = git grep -n "password" $(git rev-list --all)

# Display unique file names
$result | select -unique { $_ -replace "(^.*?:)|(:.*)", "" }

1

따라서 이전 버전의 코드를 통해 마지막으로 존재하는 곳을 찾으려고 노력하고 있습니까?

내가 이것을하고 있다면 아마도 git bisect을 사용할 것입니다 . bisect를 사용하면 알려진 양호한 버전, 알려진 나쁜 버전 및 버전이 좋은지 확인하는 간단한 스크립트 (이 경우 찾고있는 코드가 있는지 확인하는 grep)를 지정할 수 있습니다. ). 이를 실행하면 코드가 제거 된시기를 찾을 수 있습니다.


2
예, 그러나 "test"는 코드를 파악하고 코드가 있으면 "true"를 반환하고 그렇지 않으면 "false"를 반환하는 스크립트 일 수 있습니다.
Rob Di Marco

2
글쎄, 만약 개정판 10에서 코드가 잘못 되었다면, 개정판 11에서 좋게되고 개정판 15에서 다시 불량이된다면 ...
Paolo

2
Paolo에 동의합니다. 이진 검색은 "순서화 된"값에만 적합합니다. git bisect의 경우 이는 기준점에서 시작하여 모든 "좋은"개정이 모든 "나쁜"개정보다 우선 함을 의미하지만 임시 코드를 찾을 때는 가정 할 수 없습니다. 이 솔루션은 경우에 따라 작동 할 수도 있지만 일반적인 범용 솔루션은 아닙니다.
Kent

나는 전체 트리가 bisect에 대해 여러 번 체크 아웃되기 때문에 이것이 매우 비효율적이라고 생각합니다.
U. Windl

0

시나리오 : IDE를 사용하여 코드를 크게 정리했습니다. 문제 : IDE가 생각보다 많은 시간을 정리했으며 이제 코드가 컴파일되지 않습니다 (리소스 부족 등).

해결책:

git grep --cached "text_to_find"

"text_to_find"가 변경된 파일을 찾을 수 있습니다.

이제이 변경 사항을 취소하고 코드를 컴파일 할 수 있습니다.


0
git rev-list --all | xargs -n 5 git grep EXPRESSION

Jeet의 솔루션에 대한 조정 이므로 검색이 끝나고 끝이 아니라 결과가 표시됩니다 (큰 저장소에서 시간이 오래 걸릴 수 있음).


-1

필자의 경우 짧은 커밋 을 검색해야 했고 나열된 솔루션이 불행히도 작동하지 않았습니다.

나는 그것을 할 수 있었다 ( REGEX 토큰 교체 ) :

for commit in $(git rev-list --all --abbrev-commit)
do
    if [[ $commit =~ __REGEX__ ]]; then 
        git --no-pager show -s --format='%h %an - %s' $commit
    fi
done
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.