协慌网

登录 贡献 社区

如何在 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 的所有提交文本进行 grep。

在两个命令中传递路径的原因是因为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 logpickaxe( -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显示提交。