题 如何在git历史中grep(搜索)已提交的代码?


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

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

git log -p | grep <pattern>

但是,这不会立即返回提交哈希。我一起玩 git grep 无济于事。


1117
2018-05-28 11:36


起源


Junio C Hamano(git maintainer)的这些博客文章可能对你有用:* Linus的终极内容跟踪工具 (关于镐搜索,即 git log -S 和责备)* [有趣的“git log --grep”] [2](搜索提交消息)* [有趣的“git grep”] [3] [2]: gitster.livejournal.com/30195.html [3]: gitster.livejournal.com/27674.html - Jakub Narębski
可能重复 如何grep git提交某个单词
从可能重复的答案实际工作: stackoverflow.com/a/1340245/492 - CAD bloke
这个问题是它没有给出变化的任何背景......即谁/何时 - Sonic Soul


答案:


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

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 发生了,但你也需要传递给 grep 所以它只会搜索 lib/util

想象一下以下场景: grep 可能会发现相同的 <regexp> 在由其返回的同一修订中包含的其他文件上 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 diff --unified=0 | grep <pattern>

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

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

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

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

1491
2018-05-28 13:47



谢谢,效果很好!虽然需要“$(git rev-list --all)”并且没有方便的切换来指定在分支的整个历史中进行搜索,但这很令人遗憾。 - Ortwin Gentz
不幸的是,我无法通过msysgit-1.7.4实现这一目标。它告诉我 sh.exe": /bin/git: Bad file number。 VonC的答案也适用于msysgit。 - eckes
-bash:/ usr / bin / git:参数列表太长 - todd
使用xargs消除参数列表太长。 git rev-list --all | xargs git grep expression - dlowe
是的,这似乎在Windows上也失败了,唉。 - mlissner


你应该使用 镐(-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正则表达式而不是搜索字符串。


 评论说,这个搜索区分大小写 - 他打开了一个 后续问题 关于如何搜索不区分大小写的。


440
2018-05-28 11:57



谢谢,我不知道这个选项。如果您对提交消息感兴趣,看起来这是最好的解决方案,如果您需要纯行匹配的传统UNIX grep行为,Jeet的解决方案是最合适的。 - Ortwin Gentz
@Ortwin:同意(我赞成所选择的解决方案)。该 git log 在你的问题中有点困惑;) - VonC
结合它 -p 标志也输出差异。 - Sander
有没有办法使用git log -S排除匹配特定模式的所有目录? - BakaKuna
@Anentropic你需要的 --branches --all 搜索所有仓库的选项。 - VonC


我最喜欢这样做的方法是 git log-G 选项(在1.7.4版中添加)。

-G<regex>
       Look for differences whose added or removed line matches the given <regex>.

方式之间有一个微妙的区别 -G 和 -S options确定提交是否匹配:

  • -S option实质上计算在提交之前和之后您的搜索在文件中匹配的次数。如果前后计数不同,则提交将显示在日志中。例如,这不会显示提交与您的搜索匹配的行的提交。
  • 随着 -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


205
2017-09-14 18:34



有没有办法在git日志输出中显示匹配的更改上下文? - Thilo-Alexander Ginkel
@ Thilo-AlexanderGinkel - 我通常只是添加 -p 为每个提交显示差异的选项。然后当我的寻呼机打开日志时,我会搜索我正在寻找的任何内容。如果您的寻呼机是 less 你呢 git log -Ghello -p,你可以输入 /hello, 按 Enter,并使用 n 和 N 找到“你好”的下一个/上一个出现。 - 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 ;) )

33
2018-04-17 08:17



加入的解决方案对我来说既不适用于git log -S。这一个做到了! - rodvlopes


我拿了 @ Jeet的回答 并将其添加到Windows(感谢 这个答案):

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

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


22
2017-11-17 09:35



+1 - 如果你想在每次查找后避免点击“q”,请添加 --no-pager 到最后的git命令 - cgp
此外,我会注意到附加到文本文件具有实际显示匹配文本的额外优势。 (使用附加到文本文件 >>results.txt 对于那些不熟悉Windows管道的人...... - cgp
我认为bash的语法很难看:) - smido


搜索 任何修订,任何文件

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

10
2018-04-02 15:03





git log 可以是跨所有分支搜索文本的更有效方式,特别是如果有许多匹配项,并且您希望首先查看更新的(相关)更改。

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

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

找到一个添加了您正在寻找的文本的相关提交(例如,8beeff00d),找到包含提交的分支:

git branch -a --contains 8beeff00d

8
2018-06-23 00:38