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

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

一个非常糟糕的解决方案是在日志中进行grep。

git log -p | grep <pattern>

然而,这并不能直接返回提交哈希值。我用git grep玩了一下,但没有效果。

对该问题的评论 (4)
解决办法

要搜索提交的*内容(即实际的源代码行,而不是提交信息之类的),你需要做的是。

git grep  $(git rev-list --all)

git rev-list --all | xargs git grep在遇到"参数列表太长"的错误时,会起作用。

如果你想把搜索限制在某个子树上(例如,"lib/util"),你需要把它传给rev-list子命令和grep

git grep  $(git rev-list --all -- lib/util) -- lib/util

这将在你所有的提交文本中搜索 "regexp"。

之所以在两个命令中都传递路径,是因为rev-list将返回所有发生在lib/util上的修改列表,但同时你也需要传递给grep,使它只搜索lib/util

想象一下下面的情况:grep可能会在rev-list返回的同一版本中包含的其他文件上找到相同的``(即使在该版本中没有对该文件进行修改)。

这里有一些搜索源代码的其他有用方法。

搜索工作树中与正则表达式regexp匹配的文本。

git grep 

搜索工作树中符合正则表达式regexp1或regexp2的文本行。

git grep -e  [--or] -e 

搜索工作树中符合正则表达式regexp1和regexp2的文本行,仅报告文件路径。

git grep -e  --and -e 

搜索工作树中与正则表达式regexp1匹配的文本行和与正则表达式regexp2匹配的文本行的文件。

git grep -l --all-match -e  -e 

搜索工作树中与正则表达式匹配的已更改的文本行。

git diff --unified=0 | grep 

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

git grep  $(git rev-list --all)

搜索rev1和rev2之间的所有修订,寻找与正则表达式regexp匹配的文本。

git grep  $(git rev-list ..)
评论(19)

你应该使用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 history - find lost line by keyword


正如Jakub Narębski所评论的。

  • 这个寻找引入或删除``的实例的差异。
    这通常意味着"你添加或删除了带有'Foo'的行的修订案"。

  • the --pickaxe-regex选项允许你使用扩展的POSIX regex,而不是搜索一个字符串。


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

评论(7)

我最喜欢的方法是使用git log'的G选项(1.7.4版本中添加)。

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

-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" 在文件中出现的次数在这次提交前后是一样的,所以不会用 "hello "来匹配。 但是,由于有一行与 "hello "相匹配的修改,所以会用 "Ghello "来显示提交。

评论(3)

如果你想浏览代码的变化(查看整个历史中给定的词实际被修改了什么),请使用 "补丁 "模式--我发现一个非常有用的组合。

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 ;) )
评论(1)

我采用了 [@Jeet'的答案][1],并将其移植到 Windows 中(感谢 [这个答案][2])。

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

请注意,对我来说,由于某些原因,删除这个regex的实际提交并没有出现在命令的输出中,而是在它之前的一次提交中。

[1]: https://stackoverflow.com/questions/2928584/how-to-grep-in-the-git-history/2929502#2929502 [2]: https://stackoverflow.com/questions/434038/whats-the-cmd-powershell-equivalent-of-back-tick-on-bash/434087#434087

评论(3)

git log是在所有分支中搜索文本的一种更有效的方法,尤其是当有许多匹配的文本,并且你想先看到最近(相关)的变化时。

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

这些日志命令列出了添加或删除给定的搜索字符串/regex的提交,(一般来说)是最近的提交。 -p选项会显示相关的差异,所以你可以在上下文中看到它。

找到了相关的提交,并添加了你要找的文本 (例如:8beeff00d)。 8beeff00d),找到包含该提交的分支。

git branch -a --contains 8beeff00d
评论(0)

任何版本、任何文件中搜索

git rev-list --all | xargs git grep 

只在某些给定的文件中搜索,例如**XML文件。

git rev-list --all | xargs -I{} git grep  {} -- "*.xml"

结果行应该是这样的。 6988bec26b1503d45eb0b2e8a4364afb87dde7af:bla.xml: 找到的行的文本...

然后你可以用git show获得更多信息,比如作者、日期、差异。

git show 6988bec26b1503d45eb0b2e8a4364afb87dde7af
评论(0)

为了简单起见,我'建议使用GUI。 gitk - Git 仓库浏览器](https://git-scm.com/docs/gitk)。 它非常灵活

  1. 要搜索代码。

    [![在此输入图片描述][1]][1] 。
  2. 搜索文件。


    [![在此输入图像描述][2]][2]。

  3. 当然,它也支持正则表达式。
    <br/&gt。 [![在此输入图片描述][3]][3] 。

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

[1]: https://i.stack.imgur.com/3Ymk8.png [2]: https://i.stack.imgur.com/58qpA.png [3]: https://i.stack.imgur.com/U3tat.png

评论(0)

如果有人想在Sourcetree中做这件事,UI中没有直接的命令(从1.6.21.0版本开始)。 但是,你可以通过打开终端窗口(主工具栏上的按钮)并将其复制/粘贴到其中,来使用在接受的答案中指定的命令。

请注意。 Sourcetree'的搜索视图可以为你进行部分文本搜索。 按Ctrl

  • 3 进入搜索视图(或点击底部的搜索标签)。 从最右边,将搜索类型设置为文件更改,然后输入要搜索的字符串。 与上述命令相比,此方法有以下限制。
  1. Sourcetree只显示其中一个更改的文件中包含搜索词的commits。 寻找包含搜索文字的确切文件又是一项手工工作。
  2. 不支持RegEx。

评论(0)

@Jeet'的答案在PowerShell中有效。

git grep -n  $(git rev-list --all)

下面显示了所有提交中包含 "密码 "的文件。

# store intermediate result
$result = git grep -n "password" $(git rev-list --all)

# display unique file names
$result | select -unique { $_ -replace "(^.*?:)|(:.*)", "" }
评论(0)

那么,你是否试图通过旧版本的代码来寻找最后存在的东西?

如果我在做这个,我可能会使用git bisect。 使用bisect,你可以指定一个已知的好版本,一个已知的坏版本,以及一个简单的脚本,来检查这个版本是好是坏(在这个例子中,用grep来检查你要找的代码是否存在)。 运行这个脚本就可以找到该代码是什么时候被删除的。

评论(3)
git rev-list --all | xargs -n 5 git grep EXPRESSION

是对 @Jeet'解决方案的一个调整,所以它在搜索时显示结果,而不是仅仅在搜索结束时显示(在大型仓库中可能需要很长时间)。

评论(0)

场景。 你用IDE对你的代码进行了一次大清理。 问题是:IDE清理了更多的代码,现在你的代码无法编译(缺少资源等)。 IDE清理了更多的代码,现在你的代码无法编译(缺少资源等)。

解决方法: {{{7010732}}你用IDE做了一次大的清理,现在你的代码不能编译(缺少资源等)。

git grep --cached "text_to_find"

它将找到"text_to_find&quot.被修改的文件。 被修改的文件。

现在你可以撤消这个修改,然后编译你的代码。

评论(0)

每当我发现自己在你那里的时候,我都会使用以下命令行。

git log -S "" --all --oneline  --graph

解释。

  1. 它按时间顺序显示日志。
  2. -S "<单词/短语,我正在努力寻找>"-它显示了所有Git提交的文件(添加/修改/删除)中有我正在努力寻找的单词/短语,没有'<>' 符号。

  3. --all--要在所有分支中执行和搜索。

  4. --oneline--它将Git日志压缩在一行。

  5. --graph--创建按时间顺序排列的提交图。

评论(1)

在我的例子中,我需要搜索一个短提交,但不幸的是,所列出的解决方案并不奏效。

我设法用以下方法来实现。 (替换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
评论(0)