如何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转到搜索视图(或点击底部的搜索选项卡)。 从最右边,将搜索类型设置为文件更改 ,然后键入要搜索的字符串。 与上述命令相比,此方法有以下限制:
- SourceTree仅在其中一个更改的文件中显示包含搜索词的提交 。 查找包含搜索文本的确切文件也是一项手动任务。
- 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