如何grep(搜索)提交的代码在Git的历史?

过去某个时候我删除了一个文件或一些代码。 我可以grep的内容(不在提交消息)?

一个非常糟糕的解决方案是grep日志:

git log -p | grep <pattern> 

但是这不会立即返回提交散列。 我玩git grep无济于事。

要搜索提交内容 (即实际的源代码行,而不是提交消息等),你需要做的是:

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

更新git rev-list --all | xargs git grep expression 如果遇到“参数列表太长”的错误, git rev-list --all | xargs git grep expression将会起作用

如果你想限制搜索某个子树(比如“lib / util”),你需要把它传递给rev-list子命令和grep

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

这将grep通过所有提交文本的正则表达式。

在这两个命令中传递路径的原因是因为rev-list将返回lib/util发生的所有更改的修订列表,而且还需要传递给grep以便仅在lib/util上进行搜索。

试想一下下面的场景: grep可能会在rev-list返回的同一版本中包含的其他文件上找到相同的<regexp> (即使该版本上没有对该文件进行更改)。

以下是一些其他有用的搜索源的方法:

搜索工作树的文本匹配正则表达式正则表达式:

 git grep <regexp> 

匹配正则表达式regexp1或regexp2的文本行搜索工作树:

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

在匹配正则表达式regexp1和regexp2的文本行中搜索工作树,仅报告文件路径:

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

搜索工作树,查找具有匹配正则表达式regexp1的文本行和匹配正则表达式regexp2的文本行的文件:

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

搜索文本匹配正则表达式正则表达式的所有修订:

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

搜索rev1和rev2之间的所有修订文本以匹配正则表达式正则表达式:

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

你应该使用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历史记录 – 通过关键字查找丢失的行数。


正如JakubNarębski所评论的那样:

  • 这会查找引入或移除<string>实例的差异
    这通常意味着“修改你添加或删除行'Foo'”。

  • --pickaxe-regex选项允许你使用扩展的POSIX正则表达式而不是搜索字符串。


正如罗布所说,这个搜索是区分大小写的 – 他提出了一个关于如何搜索不区分大小写的后续问题 。

我最喜欢的方式是使用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显示提交。

如果你想浏览代码的变化(看看实际上已经改变了整个历史中给定的单词)去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 ;) ) 

我拿了@ Jeet的答案,并将其分配给Windows(感谢这个答案 ):

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

请注意,对于我来说,出于某种原因,删除此正则表达式的实际提交没有出现在命令的输出中,而是出现在它之前的一个提交。

在任何修订版本中搜索任何文件:

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

仅在某些给定文件中搜索,例如xml文件:

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

结果行应如下所示:6988bec26b1503d45eb0b2e8a4364afb87dde7af:bla.xml:找到的行的文本…

然后你可以使用git show获取更多的信息,如作者,日期,差异:

 git show 6988bec26b1503d45eb0b2e8a4364afb87dde7af 

对于试图在SourceTree中执行此操作的其他人,在UI中没有直接命令(从版本1.6.21.0开始)。 但是,您可以通过打开“ 终端”窗口(主工具栏中可用的按钮)并在其中复制/粘贴来使用接受的答案中指定的命令。

注意:SourceTree的搜索视图可以部分为您进行文本搜索。 按Ctrl + 3转到搜索视图(或点击底部的搜索选项卡)。 从最右边,将搜索类型设置为文件更改 ,然后键入要搜索的字符串。 与上述命令相比,此方法有以下限制:

  1. SourceTree仅在其中一个更改的文件中显示包含搜索词的提交 。 查找包含搜索文本的确切文件也是一项手动任务。
  2. RegEx不受支持。

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 bisect 。 使用bisect,你可以指定一个已知的正确版本,一个已知的错误版本,以及一个简单的脚本来检查版本是好还是坏(在这个例子中是一个grep来查看你正在查找的代码是否存在)。 运行这将发现代码被删除。

@ 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 "(^.*?:)|(:.*)", "" } 

在我的情况下,我需要搜索一个短提交和列出的解决方案不幸的是不工作。

我设法做到:(替换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