如何在 Git 历史记录中 grep(搜索)已提交的代码

我过去某个时候已经删除了文件或文件中的某些代码。我可以在内容中(而不是在提交消息中)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

这将遍历regexp所有提交文本。

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

试想一下以下情形: grep可能在rev-list返回的同一修订版中包含的其他文件上找到相同的<regexp> (即使该修订版上的文件没有更改)。

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

在工作树中搜索与正则表达式 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 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 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 正则表达式而不是搜索字符串。


正如Rob所说,此搜索区分大小写 - 他就如何搜索不区分大小写提出了一个后续问题

我最喜欢的方法是使用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 log是在所有分支中搜索文本的更有效方法,尤其是在存在许多匹配项的情况下,并且您希望首先查看最近的(相关)更改。

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

这些日志命令列出了提交,这些提交添加或删除了给定的搜索字符串 / 正则表达式(通常)是最近的。 -p选项使相关的差异显示在添加或删除模式的位置,因此您可以在上下文中看到它。

找到相关的提交后添加您要查找的文本(例如 8beeff00d),找到包含该提交的分支:

git branch -a --contains 8beeff00d

搜索任何版本,任何文件

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

为了简单起见,我建议使用 GUI: gitk-Git 存储库浏览器 。非常灵活

  1. 要搜索代码:

    在此处输入图片说明
  2. 搜索文件:

    在此处输入图片说明
  3. 当然,它也支持正则表达式:

    在此处输入图片说明

您可以使用向上 / 向下箭头浏览结果。

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

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

  1. Sourcetree 仅显示已更改文件之一中包含搜索词的提交 。查找包含搜索文本的确切文件还是手动任务。
  2. 不支持 RegEx。

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