【问题标题】:Is it possible to perform a 'grep search' in all the branches of a Git project?是否可以在 Git 项目的所有分支中执行“grep 搜索”?
【发布时间】:2013-03-08 10:58:37
【问题描述】:

是否可以在 Git 控制源项目的所有分支中运行 git grep?还是有其他命令可以运行?

【问题讨论】:

标签: git grep


【解决方案1】:

可以通过两种常见的方式来实现:Bash 或 Git 别名

这里有三个命令:

  1. git grep-branch - 在所有本地和远程分支中搜索
  2. git grep-branch-local - 仅在本地分支机构中搜索
  3. git grep-branch-remote - 仅限远程分支

用法同git grep

git grep-branch "find my text"
git grep-branch --some-grep-options "find my text"

GREP 使用:Git 别名

文件 ~/.gitconfig

应手动将命令添加到 ~/.gitconfig 文件中,因为 git config --global alias 会评估您添加的复杂代码并将其搞砸。


[alias]
    grep-branch        = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' | xargs git grep $@; };f "
    grep-branch-remote = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' | grep '^remotes' | xargs git grep $@; };f"
    grep-branch-local  = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' -e '^remotes' | xargs git grep $@;  };f "

注意:当您添加别名并且它们无法运行时 - 检查反斜杠 \bash 命令相比,它们可能需要额外的转义 \\

  • git branch -a - 显示所有分支;
  • sed -e 's/[ \\*]*//' - 修剪 空格(来自 branch -a)和 *(活动分支名称有它);
  • grep -v -e '\\->' - 忽略复杂名称,例如remotes/origin/HEAD -> origin/master
  • grep '^remotes' - 获取所有远程分支;
  • grep -v -e '^remotes' - 获取分支除了远程分支;

示例git grep-branch-local -n getTastyCookies

-n 将行号添加到匹配行的前缀。

[user@pc project]$ git grep-branch-local -n getTastyCookies

dev:53:modules/factory/getters.php:function getTastyCookies($user);
master:50:modules/factory/getters.php:function getTastyCookies($user)

目前的结构是:

: - 分隔符

  1. 分公司:dev
  2. 行号:53
  3. 文件路径:modules/factory/getters.php
  4. 匹配线:function getTastyCookies($user)

GREP 使用:BASH

您应该知道:Bash 命令应该存储在 .sh 脚本中或在 shell 中运行。

仅限本地分支机构

git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' -e '^remotes' | xargs git grep "TEXT"

仅限远程分支

git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' | grep '^remotes' | xargs git grep "TEXT"

本地和远程分支

git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' | xargs git grep "TEXT"

【讨论】:

  • 听起来不错,但我从git grep-branch "find my text" 收到了这个错误:fatal: ambiguous argument 'client': both revision and filename
  • 为什么总是使用-a,它显示所有分支?我建议使用git branch 命令的选项来分隔分支。查看本地分支时,只有一个 *,因此无需为 sed 转义它。所以:git branch | sed -e 's/*/ /' | xargs git grep "TEXT" 仅用于本地分支,git branch -r | grep -v -- "->" | xargs git grep "TEXT" 仅用于远程分支,git branch -a | grep -v -- "->" | xargs git grep "TEXT" 用于所有分支
  • 我遇到了一个稍微不同的问题,但是这个奇怪的功能解决了我的问题。谢谢你!仅供参考 - 我想删除除 master 和 dev 之外的所有本地分支。这样做的别名是:cleanLocalBranches = "!f(){ git branch -a | egrep -v '(^\\*|master|dev)' | xarg s git branch -D; };f "
【解决方案2】:

问题“How to grep (search) committed code in the git history?”建议:

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

搜索所有提交,其中应包括所有分支。

另一种形式是:

git rev-list --all | (
    while read revision; do
        git grep -F 'yourWord' $revision
    done
)

您可以在this article 中找到更多示例:

我在一个足够大的项目上尝试了上述方法,以至于 git 抱怨参数大小,所以如果遇到这个问题,请执行以下操作:

git rev-list --all | (while read rev; do git grep -e <regexp> $rev; done)

(请参阅下面此答案最后一部分中的替代方法)

如果需要,请不要忘记这些设置:

# Allow Extended Regular Expressions
git config --global grep.extendRegexp true
# Always Include Line Numbers
git config --global grep.lineNumber true

这个别名也有帮助:

git config --global alias.g "grep --break --heading --line-number"

2016 年 8 月更新:R.M. 在 cmets 中推荐

在尝试git branch 版本时,我得到了一个“fatal: bad flag '-&gt;' used after filename”。该错误与 HEAD 别名表示法有关。

我通过在管道中的trxargs 命令之间添加一个sed '/-&gt;/d' 解决了这个问题。

 git branch -a | tr -d \* | sed '/->/d' | xargs git grep <regexp>

即:

alias grep_all="git branch -a | tr -d \* | sed '/->/d' | xargs git grep"
grep_all <regexp>

这是对chernjiesuggested 的解决方案的改进,因为git rev-list --all 太过分了。

更精细的命令可以是:

# Don't use this, see above
git branch -a | tr -d \* | xargs git grep <regexp>

这将允许您仅搜索分支(包括远程分支)

您甚至可以为它创建一个 bash/zsh 别名:

# Don't use this, see above  
alias grep_all="git branch -a | tr -d \* | xargs git grep"
grep_all <regexp>

【讨论】:

  • git branch 的输出通过管道传送到tr 或sed 中不是一个好主意; git branch 是一个供人类消费的瓷器命令。请参阅stackoverflow.com/a/3847586/2562319 了解首选替代方案。
  • @jbyler 好点。具有讽刺意味的是,我早在这个答案之前就在瓷器上发布了答案:stackoverflow.com/a/6978402/6309。例如,我在stackoverflow.com/a/19206916/6309 中使用它。
  • 是的,很好。查看其他答案,我认为@errordeveloper 的答案是最干净的:stackoverflow.com/a/21284342/2562319 : "git grep $(git for-each-ref --format='%(refname)' refs/)"
  • 有没有办法显示与搜索匹配的分支名称?
  • "while read rev; do git grep -e $rev; done" 到底是做什么的?我必须按一个键才能继续观看吗?
【解决方案3】:

git log 是一种在所有分支中搜索文本的更有效方式,尤其是在有很多匹配项并且您希望首先查看最近(相关)更改的情况下。

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

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

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

git branch -a --contains 8beeff00d

【讨论】:

  • 最简单的方法!谢谢你的回答!
【解决方案4】:

我发现这个最有用:

git grep -i foo `git for-each-ref --format='%(refname)' refs/`

您需要根据是否只想查看远程分支和本地分支来调整最后一个参数,即:

  • git grep -i foo $(git for-each-ref --format='%(refname)' refs/remotes)
  • git grep -i foo $(git for-each-ref --format='%(refname)' refs/heads)

我创建的别名如下所示:

grep-refs = !sh -c 'git grep "$0" "$@" "$(git for-each-ref --format=\"%(refname)\"" refs/)'

【讨论】:

  • 有趣的别名。 +1。比我的回答更准确。
  • 如何让您的别名适用于词组搜索?当我将“foo bar”作为参数传递时,我得到:致命:不明确的参数“bar”:未知修订或路径不在工作树中。使用 '--' 将路径与修订分开
  • 尝试转义空格:"foo\ bar"
  • 这显然是公认的答案;)我已经扩展它只搜索我项目的最新分支(超过 500 个,不要问,每个 grep 大约需要 4 秒所以我不想也不需要搜索超过 100 个最新的)。为此,我已将 git for-each-ref 更新为 --sort=-committerdate --count=100 !感谢您的原创想法!
【解决方案5】:

如果您向git grep 提供任何提交的 SHA-1 哈希值,您可以在其中搜索,而不是在工作副本中搜索。

要搜索所有分支,您可以使用git rev-list --all 获取所有树。把它全部放在

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

...要有耐心

【讨论】:

    【解决方案6】:

    我是这样做的:

    git for-each-ref --format='%(*refname)' | xargs git grep SEARCHTERM
    

    【讨论】:

    • 唯一适用于 Windows 的解决方案(在 Git bash 中)
    猜你喜欢
    • 2017-07-22
    • 1970-01-01
    • 1970-01-01
    • 2011-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-03
    相关资源
    最近更新 更多