etc./StackOverFlow

Git 기록에서 커밋된 코드를 grep(검색)하는 방법

청렴결백한 만능 재주꾼 2022. 1. 8. 01:38
반응형

질문자 :Ortwin Gentz


과거 언젠가 파일이나 파일의 일부 코드를 삭제했습니다. 내용에서 grep할 수 있습니까(커밋 메시지가 아님)?

매우 열악한 솔루션은 로그를 grep하는 것입니다.

 git log -p | grep <pattern>

그러나 이것은 커밋 해시를 바로 반환하지 않습니다. 나는 git grep 으로 아무 소용이 없었습니다.



커밋 내용 (즉, 커밋 메시지와 반대되는 실제 소스 줄)을 검색하려면 다음을 수행해야 합니다.

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

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

검색을 일부 하위 트리(예: "lib/util")로 제한하려면 이를 rev-list 하위 명령과 grep 에도 전달해야 합니다.

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

regexp 대한 모든 커밋 텍스트를 grep합니다.

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

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

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

정규 표현식 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>)

Jeet

git log의 곡괭이( -S ) 옵션을 사용해야 합니다.

Foo 를 검색하려면:

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

자세한 내용은 Git 기록 - 키워드별로 잃어버린 줄 찾기를 참조하세요.


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

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

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


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


VonC

내가 가장 좋아하는 방법은 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 사용하여 표시됩니다.


Tyler Holien

코드 변경 사항을 검색하려면(전체 기록에서 주어진 단어로 실제로 변경된 사항 참조) 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 ;) )

Bartek Skwira

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

Edward Anderson

모든 버전, 모든 파일 (unix/linux)에서 검색:

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

XML 파일과 같이 지정된 일부 파일에서만 검색:

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

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

git show 사용하여 작성자, 날짜 및 diff와 같은 추가 정보를 얻을 수 있습니다.

 git show 6988bec26b1503d45eb0b2e8a4364afb87dde7af

Christophe Roussy

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

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

어떤 이유에서인지 이 정규식을 삭제한 실제 커밋은 명령 출력에 나타나지 않고 그 이전의 커밋 하나에 나타납니다.


ripper234

단순화를 위해 GUI를 사용하는 것이 좋습니다. gitk - The Git 저장소 브라우저 . 꽤 유연하다

  1. 코드를 검색하려면:

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

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

    여기에 이미지 설명 입력

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


watashiSHUN

나는 당신의 자리에 있을 때마다 다음 명령줄을 사용합니다.

 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 - 시간순으로 정렬된 커밋의 그래프를 생성합니다.

surajs1n

Sourcetree 에서 이 작업을 시도하는 다른 사람의 경우 UI에 직접 명령이 없습니다(버전 1.6.21.0 현재). 그러나 터미널 창(메인 도구 모음에서 사용 가능한 버튼)을 열고 거기에 복사/붙여넣기를 하면 수락된 답변에 지정된 명령을 사용할 수 있습니다.

참고: Sourcetree의 검색 보기는 부분적으로 텍스트 검색을 수행할 수 있습니다. Ctrl + 3 을 눌러 검색 보기로 이동합니다(또는 하단에 있는 검색 탭을 클릭). 맨 오른쪽에서 검색 유형을 파일 변경으로 설정한 다음 검색하려는 문자열을 입력합니다. 이 방법은 위의 명령에 비해 다음과 같은 제한 사항이 있습니다.

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

dotNET

답변 https://stackoverflow.com/a/2929502/6041515 에서 영감을 받아 git grep 이 diff뿐만 아니라 각 커밋에서 전체 코드 기반을 검색하는 것으로 나타났습니다. 결과는 반복적이고 길었습니다. 아래의 이 스크립트는 대신 각 git 커밋의 diff만 검색합니다.

 for commit in $(git rev-list --all); do # search only lines starting with + or - if git show "$commit" | grep "^[+|-].*search-string"; then git show --no-patch --pretty=format:'%C(yellow)%h %Cred%ad %Cblue%an%Cgreen%d %Creset%s' --date=short $commit fi done

예제 출력, 맨 아래 git 커밋은 내가 찾고 있는 변경 사항을 처음 도입한 것입니다.

 csshx$ for commit in $(git rev-list --all); do > if git show "$commit" | grep "^[+|-].*As csshX is a command line tool"; then > git show --no-patch --pretty=format:'%C(yellow)%h %Cred%ad %Cblue%an%Cgreen%d %Creset%s' --date=short $commit > fi > done +As csshX is a command line tool, no special installation is needed. It may 987eb89 2009-03-04 Gavin Brock Added code from initial release

Dichen

이미 존재하는 답변에 더 많은 것을 추가합니다. 만들 수 있는 파일을 알고 있는 경우 다음을 수행합니다.

 git log --follow -p -S 'search-string' <file-path>

--follow: 파일의 히스토리를 나열합니다.


Vinita Maloo

자, 오늘 두 번이나 hg grep 대해 더 가까운 것을 원하는 사람들을 보았습니다. 이는 git log -pS 와 비슷하지만 출력을 (주석이 있는) 변경된 행으로 제한합니다.

빠른 개요를 보고 싶다면 호출기에서 /pattern/ 보다 더 편리할 것 같습니다.

git log --pretty=%h -p 출력을 취하고 주석이 달린 변경 라인을 뱉어내는 diff-hunk 스캐너가 있습니다. 그것을 diffmarkup.l 에 넣고, 예를 들어 make ~/bin/diffmarkup 과 같이 사용하십시오.

 git log --pretty=%h -pS pattern | diffmarkup | grep pattern
 %option main 8bit nodefault // vim: tw=0 %top{ #define _GNU_SOURCE 1 } %x commitheader %x diffheader %x hunk %% char *afile=0, *bfile=0, *commit=0; int aline,aremain,bline,bremain; int iline=1; <hunk>\n ++iline; if ((aremain+bremain)==0) BEGIN diffheader; <*>\n ++iline; <INITIAL,commitheader,diffheader>^diff.* BEGIN diffheader; <INITIAL>.* BEGIN commitheader; if(commit)free(commit); commit=strdup(yytext); <commitheader>.* <diffheader>^(deleted|new|index)" ".* {} <diffheader>^"---".* if (afile)free(afile); afile=strdup(strchrnul(yytext,'/')); <diffheader>^"+++".* if (bfile)free(bfile); bfile=strdup(strchrnul(yytext,'/')); <diffheader,hunk>^"@@ ".* { BEGIN hunk; char *next=yytext+3; #define checkread(format,number) { int span; if ( !sscanf(next,format"%n",&number,&span) ) goto lostinhunkheader; next+=span; } checkread(" -%d",aline); if ( *next == ',' ) checkread(",%d",aremain) else aremain=1; checkread(" +%d",bline); if ( *next == ',' ) checkread(",%d",bremain) else bremain=1; break; lostinhunkheader: fprintf(stderr,"Lost at line %d, can't parse hunk header '%s'.\n",iline,yytext), exit(1); } <diffheader>. yyless(0); BEGIN INITIAL; <hunk>^"+".* printf("%s:%s:%d:%c:%s\n",commit,bfile+1,bline++,*yytext,yytext+1); --bremain; <hunk>^"-".* printf("%s:%s:%d:%c:%s\n",commit,afile+1,aline++,*yytext,yytext+1); --aremain; <hunk>^" ".* ++aline, ++bline; --aremain; --bremain; <hunk>. fprintf(stderr,"Lost at line %d, Can't parse hunk.\n",iline), exit(1);

jthill

마지막으로 존재하는 위치를 확인하기 위해 이전 버전의 코드를 grep하려고 합니까?

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


Rob Di Marco

Jet의 답변 은 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 "(^.*?:)|(:.*)", "" }

Shaun Luttin

시나리오: IDE를 사용하여 코드를 크게 정리했습니다. 문제: IDE가 필요 이상으로 정리되었지만 이제 코드가 컴파일되지 않습니다(리소스 누락 등).

해결책:

 git grep --cached "text_to_find"

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

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


Garytech

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

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


laktak

출처 : http:www.stackoverflow.com/questions/2928584/how-to-grep-search-committed-code-in-the-git-history

반응형