log - git高级用法




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

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

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

git log -p | grep <pattern>

但是,这不会立即返回提交散列。 我玩弄git 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 "(^.*?:)|(:.*)", "" }

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 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 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

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

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

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

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

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


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

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 diff --unified=0 | grep <pattern>

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

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

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

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

git rev-list --all | xargs -n 5 git grep EXPRESSION

是对@Jeet解决方案的调整,因此它在搜索时显示结果,而不仅仅是结尾(在大型回购中可能需要很长时间)。





diff