一个非常糟糕的解决方案是grep日志:
git log -p | grep <pattern>
但是,这不会立即返回提交哈希。我在玩
git grep
时无济于事。#1 楼
要搜索提交内容(即,实际的源代码行,而不是提交消息等),您需要执行以下操作: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
的所有提交文本。在两个命令中传递路径的原因是因为
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)
搜索rev1和rev2之间的所有修订以查找与正则表达式regexp相匹配的文本:
git grep <regexp> $(git rev-list <rev1>..<rev2>)
评论
谢谢,效果很好!遗憾的是,虽然需要“ $(git rev-list --all)”,并且没有方便的开关来指定分支的整个历史记录。
– Ortwin Gentz
2010年5月28日在21:24
优秀的。 +1。 GitBook添加了一些详细信息(book.git-scm.com/4_finding_with_git_grep.html),Junio C Hamano阐述了您的一些观点:gitster.livejournal.com/27674.html
–VonC
2010年5月28日在21:26
不幸的是,我无法使用msysgit-1.7.4进行此操作。它告诉我sh.exe“:/ bin / git:文件号错误。VonC的答案也适用于msysgit。
–eckes
2011年7月15日在8:46
如果在使用rev-list调用git grep历史记录时收到“无法读取树”错误,则可能需要清理。尝试git gc或签出:stackoverflow.com/questions/1507463/…
–安东尼·帕诺佐(Anthony Panozzo)
2011-10-28 20:14
是的,这似乎在Windows上也失败了。
– mlissner
2012年11月28日0:39
#2 楼
您应该使用-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历史记录-查找丢失的行
,正如JakubNarębski所评论的那样:
,这将寻找引入或删除
<string>
实例的差异。它通常表示“使用'Foo'添加或删除行的修订”。
--pickaxe-regex
选项允许您使用扩展的POSIX正则表达式而不是搜索字符串。示例(来自
git log
):git log -S"frotz\(nitfol" --pickaxe-regex
正如Rob所说,此搜索区分大小写-他就如何搜索不区分大小写提出了一个后续问题。
评论
谢谢,我不知道这个选项。如果您对提交消息感兴趣,那么这似乎是最好的解决方案,而如果您需要传统的纯行匹配UNIX grep行为,那么Jeet的解决方案是最合适的。
– Ortwin Gentz
2010年5月28日在21:20
@Ortwin:同意(我已经投票赞成选择的解决方案)。您问题中的git log位让我感到困惑;)
–VonC
2010年5月28日在21:29
将其与-p标志结合使用也可以输出diff。
–桑德
14年6月19日在10:42
有什么办法可以使用git log -S排除所有匹配特定模式的目录?
– BakaKuna
2014-12-18 10:48
@Anentropic您将需要--branches --all选项来搜索所有回购。
–VonC
2015年12月10日在20:35
#3 楼
我最喜欢的方法是使用git log
的-G
选项(在版本1.7.4中添加)。-G<regex>
Look for differences whose added or removed line matches the given <regex>.
-G
和-S
选项确定提交是否匹配:-S
选项本质上计算的是在提交之前和之后搜索在文件中匹配的次数。如果前后计数不同,则提交将显示在日志中。例如,这不会显示提交,将匹配搜索的行移动到哪里。使用
-G
选项,如果您的搜索与添加,删除或更改的任何行匹配,提交将显示在日志中。 br /> 以该提交为例:
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
显示提交。评论
有没有办法在git日志输出中显示匹配的更改上下文?
– Thilo-Alexander Ginkel
2014年7月7日在9:20
@ Thilo-AlexanderGinkel-我通常只添加-p选项以显示每次提交的差异。然后,当在我的寻呼机中打开日志时,我将搜索所需的内容。如果您的寻呼机较少,并且您在git log -Ghello -p上输入,您可以键入/ hello,按Enter键,并使用n和N查找下一个/上一个出现的“ hello”。
–泰勒·霍利安(Tyler Holien)
2014年7月7日在13:54
我发现-G和Regex有一个有趣的问题:如果命令行使用UTF-8,并且您正在查看的文件使用某些ISO-Latin(8位)编码,。*将会失败。例如,我更改了Vierter Entwurf->FünfterEntwurf,而“ V. * ter Entwurf”产生了一个匹配项,而“ F. * ter Entwurf”却没有。
– U. Windl
2月22日在1:08
#4 楼
如果要浏览代码更改(查看整个历史记录中给定单词实际更改的内容),请使用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 ;) )
评论
git log -S都对我不起作用。这一个!
–杆状斜坡
2014年5月20日13:33
我认为这种交互模式是最有效的。但是,发现事件后如何获取提交ID?
–克里斯蒂安(CristianTraìna)
8月27日8:38
@CristianTraìna向上滚动,您应该看到“ commit SHA1”
– Bartek Skwira
8月28日9:32
#5 楼
git log
是在所有分支中搜索文本的更有效方法,尤其是在存在许多匹配项的情况下,并且您想先查看更多的最新(相关)更改。git log -p --all -S 'search string'
git log -p --all -G 'match regular expression'
这些日志命令列表提交会添加(或删除)给定的搜索字符串/正则表达式(通常是最近的)。
-p
选项使相关的差异显示在添加或删除模式的位置,因此您可以在上下文中看到它。找到了相关的提交,该提交添加了您要查找的文本(例如,8beeff00d),找到包含提交的分支:
git branch -a --contains 8beeff00d
评论
嗨,这些行似乎根本不起作用。我的命令是> git log -p --all -S'public string DOB {get;组; } = string.Empty;'每次我尝试运行它时,我都会得到>致命:模棱两可的参数'string':未知版本或不在工作树中的路径。 >使用'-'将路径与修订分开,如下所示:>'git <命令> [<修订> ...]-[<文件> ...]'
–user216652
2月18日15:34
@ user216652由于某种原因,引号不会将您的搜索字符串作为单个参数分组在一起。取而代之的是,“ public是-S的参数,它将其余部分视为单独的参数。我不确定您在哪个环境中运行,但是该上下文对于帮助进行故障排除是必要的。我建议您在需要时打开一个单独的StackOverflow问题,以帮助您解决git命令如何发送到shell的所有情况。在我看来,它是通过其他命令发送的?这里的评论不是正确的解决之道。
–爱德华·安德森(Edward Anderson)
2月18日19:29
#6 楼
我接受了Jeet的答案并将其调整为适用于Windows(感谢此答案):FOR /F %x IN ('"git rev-list --all"') DO @git grep <regex> %x > out.txt
请注意,出于某种原因,删除该正则表达式的实际提交确实对我有所帮助不会出现在命令的输出中,而是出现在命令的输出之前。
评论
+1-并且,如果您想避免在每次查找后都点击“ q”,请在末尾的git命令中添加--no-pager
–cgp
2012年3月28日14:04
另外,我会指出,附加到文本文件具有实际显示匹配文本的附加优势。 (对于没有精通Windows管道的用户,使用>> results.txt附加到文本文件中...
–cgp
2012年3月28日14:08
而且我认为bash的语法很丑陋:)
–smido
18年5月22日在14:43
#7 楼
在任何版本中搜索任何文件(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
获得更多信息,例如作者,日期和差异:#8 楼
为了简单起见,我建议使用GUI:gitk-Git存储库浏览器。这非常灵活要搜索代码:
要搜索文件:
当然,它还支持正则表达式:
您可以使用向上/向下箭头浏览结果。
#9 楼
每当我发现自己在您的位置时,都会使用以下命令行:git log -S "<words/phrases i am trying to find>" --all --oneline --graph
说明:
git log
-我需要在这里写更多吗?它按时间顺序显示日志。-S "<words/phrases i am trying to find>"
-它显示所有那些Git提交,其中任何文件(添加/修改/删除)都带有我要查找的单词/短语,而没有'<>'符号。--all
-强制执行和搜索所有分支。--oneline
-它将Git日志压缩到一行。--graph
-它创建按时间顺序排列的提交图。评论
“只要我发现自己在您的位置,我就会感到需要使用git!”
– Sebi
19-10-21在14:03
#10 楼
对于任何其他试图在Sourcetree中执行此操作的人,UI中都没有针对它的直接命令(自1.6.21.0版开始)。但是,您可以通过打开“终端”窗口(主工具栏中的按钮)并在其中复制/粘贴来使用接受的答案中指定的命令。注意:Sourcetree的“搜索”视图可以部分地进行文本搜索您。按Ctrl + 3转到“搜索”视图(或单击底部的“搜索”选项卡)。从最右边,将“搜索类型”设置为“文件更改”,然后键入要搜索的字符串。与上述命令相比,此方法具有以下限制:
Sourcetree仅显示其中一个更改文件中包含搜索词的提交。查找包含搜索文本的确切文件还是手动任务。
不支持RegEx。
#11 楼
好的,今天两次,我见过人们想要更接近hg grep
的值,就像git log -pS
一样,但是将其输出限制在(带注释的)已更改的行中。我想这比分页器中的
/pattern/
更方便您可以快速浏览一下。因此,这是一台diff-hunk扫描仪,它接收
git log --pretty=%h -p
输出并吐出带注释的更改行。将其放在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);
一样使用
#12 楼
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 "(^.*?:)|(:.*)", "" }
#13 楼
那么,您是否要尝试通过代码的旧版本进行grep查找以查找最后存在的内容?如果我这样做,则可能会使用git bisect。使用bisect,您可以指定一个已知的良好版本,一个已知的不良版本以及一个简单的脚本,该脚本进行检查以查看该版本的好坏(在这种情况下,将使用grep来查看您要查找的代码是否存在) )。运行此命令将查找代码被删除的时间。
评论
是的,但是您的“测试”可以是一个脚本,可以对代码进行检查,如果代码存在,则返回“ true”,否则,则返回“ false”。
–罗布·迪·马可(Rob Di Marco)
2010年6月1日,12:43
好吧,如果代码在修订版10中不好,在修订版11中很好,然后在修订版15中又变得不好...
–保罗
13-10-29在11:21
我同意保罗。二进制搜索仅适用于“有序”值。对于git bisect,这意味着从参考点开始,所有“好”修订都在所有“坏”修订之前,但是在寻找临时代码时无法做此假设。在某些情况下,此解决方案可能会起作用,但它不是一个好的通用解决方案。
–肯特
2014年3月18日15:17
我认为这是非常低效的,因为整棵树被多次检查为二等分。
– U. Windl
2月22日在1:20
#14 楼
git rev-list --all | xargs -n 5 git grep EXPRESSION
是Jeet解决方案的一项调整,因此它在搜索时显示结果,而不仅仅是在结束时显示(在大型存储库中可能要花费很长时间)。
评论
对于任何好奇的人,它通过一次在5个修订版上运行git grep来提供“实时”结果。
– DylanYoung
11月21日3:48
#15 楼
场景:您使用自己的IDE进行了代码的大清理。问题:IDE清理了过多的代码,现在您的代码无法编译(缺少资源等)。
解决方案:
git grep --cached "text_to_find"
它将找到“ text_to_find”已更改的文件。
您现在可以撤消此更改并编译您的文件代码。
#16 楼
在已经存在的答案中添加更多内容。如果您知道制作文件所在的位置,请执行以下操作:
git log --follow -p -S 'search-string' <file-path>
-关注:列出文件的历史记录
评论
Junio C Hamano(git维护者)的这些博客文章可能对您来说很有趣:* Linus的最终内容跟踪工具(关于镐搜索,即git log -S和blame)* [有趣的是“ git log --grep”] [2] (搜索提交消息)* [与“ git grep”一起使用]] [3] [2]:gitster.livejournal.com/30195.html [3]:gitster.livejournal.com/27674.html如何重复grep git提交某个单词的可能
可能重复的答案实际上有效:stackoverflow.com/a/1340245/492
这样做的问题是它没有为更改提供任何上下文信息。即,谁/何时