使用Git,我该如何在所有分支中搜索字符串?

312
使用Git,在所有本地分支的所有文件中搜索给定字符串,应该如何操作?
GitHub特定问题:是否可以在GitHub的所有分支上执行上述搜索? (我的远程GitHub存储库上有几个远程分支,理想情况下我不希望为此搜索下载它们...)

1
git-grep 可能是你正在寻找的,但我还不确定你需要哪些选项... - johnny
可能是重复的问题,关于如何在Git历史记录中搜索已提交的代码,可以参考这个链接:https://dev59.com/7nA85IYBdhLWcg3wHv3B。 - nekketsuuu
8个回答

264

你可以在Git仓库上执行这个操作:

git grep "string/regexp" $(git rev-list --all)

GitHub高级搜索具有代码搜索功能:

代码搜索将浏览GitHub上公开托管的所有代码。您还可以按以下方式进行过滤:

  • 语言:language:
  • 存储库名称(包括用户名):repo:
  • 文件路径:path:

20
这并不是做这件事的最佳方式。它不能控制传递给“git grep ...”的git引用数量。看一下其他答案,它们比这个答案要好得多,尽管它被标记为被采纳的答案! - slm
2
如果您能为您的过滤器添加一个示例,例如 path:,那将非常好,因为一眼看去的文档并不清楚在哪里应用此过滤器,我假设它在您的查询示例中的引号之前? - blamb
3
如何只列出分支名称?目前它会列出所有包含该字符串的哈希值。 - harryfeng
12
Github 搜索仅在主分支上进行。来自 https://help.github.com/articles/searching-code/ 的说明:“只有默认分支被编入代码搜索索引中。在大多数情况下,这将是主分支。” - RedPanda
3
这仅适用于相对较小的git存储库。一个git sha是40个字符加上它们之间的空格(或LF)。在Linux上,您的参数列表限制为128kb(在Mac上为256kb)。在3k-4k次提交后(在Mac上为6k-8k),您的参数列表将变得过于庞大。这在一个相当大的存储库中并不算不合理。 - stuckj
显示剩余7条评论

202

1
此外,这似乎更兼容其他类型的控制台,如fishshell。 - Daniel
5
谢谢!我使用ZSH,这个方法有效,而@manojlds的命令出现了你提到的错误!但是请注意,对于一个有着悠久历史的大型代码库,这可能需要非常长的时间。 - lacostenycoder
3
如果你想要查找特定文件中的内容,可以使用以下命令: git rev-list --all | xargs -J % git grep "string/rexexp" % -- filename。这个命令会在所有提交的代码块中运行 git grep 命令,并在代码块中 % 出现的地方插入指定的文件进行搜索。 - rgov
@rgov -J 参数的作用是什么?因为 xargs -J 在某些版本的 xargs 中似乎不存在:https://man7.org/linux/man-pages/man1/xargs.1.html - Jann Poppinga
这个标志可能只适用于 macOS/BSD。 xargs -I%echo% 将为每个输入行运行一次 echo <input line>xargs -J%echo% 将运行 echo <input line 1> <input line 2> <input line 3> ...,对于尽可能多的输入行放在一个命令中,从而减少调用次数。使用 -I 也可以,但会调用更多次 git grep - rgov

140

在很多情况下,git rev-list --all可能会返回大量提交记录,需要花费很长时间进行扫描。如果你只想搜索所有分支的最新提交,而不是搜索仓库历史中每个分支的每个提交记录,可以使用git show-ref -s --heads来替换它。所以总体上:

git grep "string" `git show-ref -s --heads`

或:
git show-ref -s --heads | xargs git grep "string"

提示:您可以将输出写入文件以便在编辑器中查看:

nano ~/history.txt
git show-ref -s --heads | xargs git grep "search string here" >> ~/history.txt

14
git show-ref --heads 列出了哈希值和引用名称,因此它会进行两次搜索(第二行)。所以 git show-ref --heads | cut -d' ' -f2 更好,因为它只列出了引用名称。 - hIpPy
8
我简直不敢相信这个问题已经被问答了多少次,但你是唯一一个给出正确答案的人。 - Sammitch
6
git show-ref --heads -s 命令只输出SHA1哈希值。如果多个分支指向同一个提交,则会有重复。可以使用 sort -u 去掉重复项,例如 git show-ref --heads -s | sort -u | xargs git grep ... - Steve
3
这是我添加到bashrc的函数,希望能帮到别人:function gsearch { git grep $1 $(git show-ref --heads) | grep "refs/heads" | grep $1 } # 最后一个grep用于保持颜色高亮显示 - AFP_555
6
这应该是被接受的答案。在所有分支中搜索字符串 但仅针对最新内容 是非常常见的用例。 - dr_
在所有分支中进行不区分大小写的搜索,根据文件扩展名过滤: git grep -i "string" `git show-ref --heads | cut -d' ' -f2` -- '*.json' - user3100212

41

这里列出的解决方案存在一些问题(即使是被接受的)。

你不需要列出所有的哈希值,因为会重复。此外,这需要更多时间。

它基于这个思路:你可以在多个分支 masterdev 上搜索字符串 "test -f /"

git grep "test -f /" master dev

这与

printf "master\ndev" | xargs git grep "test -f /"

那么开始吧。

这会找到所有本地分支的最新提交哈希值,并只在这些提交中搜索:

git branch -v --no-abbrev | awk -F' *' '{print $3}' | xargs git grep "string/regexp"
如果你需要在远程分支中搜索,那么请添加-a参数:
git branch -a -v --no-abbrev | awk -F' *' '{print $3}' | xargs git grep "string/regexp"

此外:

# Search in local branches
git branch | cut -c3- | xargs git grep "string"

# Search in remote branches
git branch -r | cut -c3- | xargs git grep "string"

# Search in all (local and remote) branches
git branch -a | cut -c3- | cut -d' ' -f 1 | xargs git grep "string"

# Search in branches, and tags
git show-ref | grep -v "refs/stash" | cut -d' ' -f2 | xargs git grep "string"

16
至少要搜索所有分支,需运行以下命令:git branch -a | cut -c3- | cut -d' ' -f 1 | xargs git grep "string"否则,在文件列表中出现带有 -> 符号的内容时会失败,该符号表示本地与远程分支之间的关系。 - Ilya Sheershoff
2
这个评论,就在我的评论上面,是正确的答案!它是唯一一个没有出错的。 - user3147973
有没有办法从这里获取分支名称? - Stefan
谢谢@IlyaSheershoff!你还需要在远程分支搜索中添加cut -d' ' -f 1 - Anurag Pande
一个更简单(和更健壮)的替代cut / awk操作的方法是使用 git branch--format 参数: git branch -a --format“%(refname)” 只返回引用名称(每行一个)。 - creinig

21

你可以尝试这个:

git log -Sxxxx  # Search all commits
git log -Sxxxx  --branches[=<pattern>]   # Search branches

11
跨所有分支:git log --all -s"搜索字符串" - Tim Kuipers
10
以上需要大写字母 S。 - barnhillec
这有助于找到包含子模块指向其远程缺失提交的提交。即形式为:fatal: git upload-pack: not our ref <hash>的错误。谢谢! - undefined

4

跟随@peter-mortensen和manojlds的解决方案,我使用git for-each-ref作为子命令来列出仅包含名称的分支。

git grep "string/regexp" $(git for-each-ref --format='%(refname:short)' refs/heads)

这样做可以更好地展现,仅显示具名分支并为每个分支生成一个结果。


1
为了在搜索结果中显示分支名称,您可以使用循环单独搜索每个分支,如下所示:
bash 代码
for branch in $(git branch | awk '{print $1}'); do
    echo "Branch: $branch"
    git grep "SEARCH_WORD" $(git rev-parse $branch)
done

这个循环使用git branch来列出所有分支,然后使用awk提取分支名称。然后,它使用git rev-parse获取每个分支的提交哈希,并使用git grep在该分支中搜索字符串"deleteTemplateDocument"。 输出将显示每个分支的分支名称和匹配结果。
git log -S <search string> --source --all

https://dev59.com/sW025IYBdhLWcg3wwYz4#5816177

撤销一个提交,提交 ID 可能不在 HEAD

git revert commit_id

-1

要忽略大小写,请使用-i:

git log -i --all --grep='word1 Word2'

5
似乎这也是第一个提到 --grep 的答案。实际上,这可能是因为它搜索的是 git 日志而不是所有分支中的文件内容,对吗?因此,它并不完全符合问题的要求。 - Andras Deak -- Слава Україні

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接