首页 文章

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

提问于
浏览
1174

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

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

git log -p | grep <pattern>

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

13 回答

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

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

  • 23

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


    正如Jakub Narębski评论的那样:

    • 这个 looks for differences that introduce or remove an instance of <string> .
      它通常意味着"revisions where you added or removed line with 'Foo'" .

    • --pickaxe-regex 选项允许您使用扩展的POSIX正则表达式而不是搜索字符串 .


    正如Rob评论的那样,这个搜索区分大小写 - 他打开了一个关于如何搜索不区分大小写的follow-up question .

  • 38

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

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

    • SourceTree仅显示其中一个已更改文件中包含搜索词的提交 . 查找包含搜索文本的确切文件也是一项手动任务 .

    • 不支持RegEx .

  • 2

    我拿了@Jeet's answer并将其附加到Windows(感谢this answer):

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

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

  • 6

    在我的情况下,我需要搜索一个Short Commit,遗憾的是列出的解决方案无效 .

    我设法用:(替换 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
    
  • 461

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

  • 5

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

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

    如果遇到"Argument list too long"错误, Updatesgit 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>)
    
  • 0

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

    @ 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 "(^.*?:)|(:.*)", "" }
    
  • 1564

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

    如果我这样做,我可能会使用git bisect . 使用bisect,您可以指定已知的正常版本,已知的错误版本以及检查版本是好还是坏的简单脚本(在这种情况下是grep,以查看您要查找的代码是否存在) . 运行此命令将在删除代码时找到 .

  • 216

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

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

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

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

    git branch -a --contains 8beeff00d
    
  • 1

    为简单起见,我建议使用GUI:gitk - The Git repository browser,它非常灵活

    • 搜索代码:
      enter image description here

    • 搜索文件:
      enter image description here

    • 因为它也支持正则表达式:
      enter image description here

    您可以使用向上/向下箭头浏览结果

  • 14

    在_351210中搜索:

    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
    

相关问题