如何从 git grep 搜索中排除某些目录/文件

Posted

技术标签:

【中文标题】如何从 git grep 搜索中排除某些目录/文件【英文标题】:How to exclude certain directories/files from git grep search 【发布时间】:2012-05-12 11:33:57 【问题描述】:

在使用git grep 搜索 git 存储库时,有没有办法排除某些路径/目录/文件?类似于普通grep 命令中的--exclude 选项?

我需要使用git grep,因为直接使用grep 在大型git 存储库上运行速度太慢。

【问题讨论】:

在 bash 上执行此操作可能是一种解决方法:***.com/questions/216995/… 此功能是在 1.9.0 中添加的 see my answer below 【参考方案1】:

在 git 1.9.0 中,“魔法词”exclude 被添加到 pathspecs。所以如果你想在每个文件中搜索foobar,除了那些匹配*.java的文件,你可以这样做:

git grep foobar -- ':(exclude)*.java'

或者使用!“短格式”排除:

git grep foobar -- ':!*.java'

请注意,在 v2.12 之前的 git 版本中,当使用排除 pathspec 时,您必须至少有一个“包含”pathspec。在上面的示例中,您还想在-- 之后的某个位置添加./*(递归地包括当前目录下的所有内容)。在 git v2.13 中,这个限制被解除,git grep foobar -- ':!*.java' 在没有 ./* 的情况下也可以工作。

在git-scm.com(或只是git help glossarypathspec 中允许的所有“魔法词”都有一个很好的参考。

【讨论】:

git grep clock.gettime -- './*' ':!arch/**' ':!drivers/**' 排除多个完整目录。我不认为它会阻止递归。 为了经常使用,您可以使用排除项创建一个 git 别名:git config alias.mygrep '!git grep "$@" -- "$GIT_PREFIX/*" ":!*.java*" #'。然后只需git mygrep foobar。 (使用别名shell # trick 和current dir。) @elonderin 此解决方案与匹配文件的报告方式无关。但我只是从子目录中尝试了git grepgit ls-files,并且都报告了相对于当前目录的文件名(即使您使用':(top)' 包含路径规范)。这两个命令都有 --full-name 选项来报告相对于根的名称,但默认情况下是关闭的。 我不使用 git 别名,所以我做了一个 bash 函数,但可能 git 别名更好gist.github.com/cmdcolin/04e2378b60f4457a41904c659368066f 我使用的是 git 2.19,比上面发布的更简单的语法就是:git grep foobar ':!*.java'【参考方案2】:

更新:对于 git >= 1.9,原生支持排除模式,请参阅 onlyone's answer。

这可能看起来倒退,但您可以将与您的排除模式不匹配的文件列表传递给git grep,如下所示:

git grep <pattern> -- `git ls-files | grep -v <exclude-pattern>`

grep -v 返回与&lt;exclude-pattern&gt; 匹配的每个路径。请注意,git ls-files 也采用 --exclude 参数,但这仅适用于未跟踪的文件

【讨论】:

谢谢! Git grep 比 ack & co 快得多,但不能排除任意路径有点太不方便了 :) 不幸的是我的仓库有很多文件。当我尝试@kynan 的方法时,我得到:“-bash: /usr/bin/git: Argument list too long” 这应该解决 Benissimo 的“参数列表太长”问题和我的 bash 解释的文件名字符(如 [])或存储库中包含空格的文件名的问题:git ls-files | grep -v | xargs -d '\n' git grep -- Check onlynone 的答案,现在可能完全在(现代版本的)git 中做到这一点。 为什么投反对票?这个答案仍然适用于 1.9 之前的 git 版本。我添加了一个关于 onlyone 答案的注释。【参考方案3】:

这是不可能的,但has been discussed recently。链接中建议的解决方法:

你可以把*.dll 放到.gitignore 文件然后git grep --exclude-standard

编辑见onlynone's answer,因为 git 1.9.0 是可能的。

【讨论】:

这曾经是真的,但现在不再是这样了,现在在 git 中是可能的。看看下面的真正答案应该是什么:***.com/a/30084612/1391445【参考方案4】:

您可以通过在存储库中创建属性文件来将文件或目录标记为二进制文件,例如

$ cat .git/info/attributes 
directory/to/ignore/*.* binary
directory/to/ignore/*/*.* binary
another_directory/to/also/ignore/*.* binary

二进制文件中的匹配项不包括包含行,例如

$ git grep "bar"
Binary file directory/to/ignore/filename matches
other_directory/other_filename:      foo << bar - bazz[:whatnot]

【讨论】:

这实际上是一个很好的答案。 我发现dir-i-wanted-to-ignore/**/* binary 成功了。 最佳答案。也可以通过使用.gitattributes 而不是本地.git/info/attributes 来提交到repo。【参考方案5】:

以@kynan 的示例为基础,我制作了这个脚本并将其作为gg 放在我的路径(~/bin/)中。它确实使用了git grep,但避免了一些指定的文件类型。

在我们的 repo 中有很多图像,所以我排除了图像文件,如果我搜索整个 repo,这会将 serchtime 降低到 1/3。但是可以轻松修改脚本以排除其他文件类型或geleralpatterns。

#!/bin/bash                                                                    
#                                                                              
# Wrapper of git-grep that excludes certain filetypes.                         
# NOTE: The filetypes to exclude is hardcoded for my specific needs.           
#                                                                              
# The basic setup of this script is from here:                                 
#   https://***.com/a/14226610/42580                                  
# But there is issues with giving extra path information to the script         
# therefor I crafted the while-thing that moves path-parts to the other side   
# of the '--'.                                                                 

# Declare the filetypes to ignore here                                         
EXCLUDES="png xcf jpg jpeg pdf ps"                                             

# Rebuild the list of fileendings to a good regexp                             
EXCLUDES=`echo $EXCLUDES | sed -e 's/ /\\\|/g' -e 's/.*/\\\.\\\(\0\\\)/'`      

# Store the stuff that is moved from the arguments.                            
moved=                                                                         

# If git-grep returns this "fatal..." then move the last element of the        
# arg-list to the list of files to search.                                     
err="fatal: bad flag '--' used after filename"                                 
while [ "$err" = "fatal: bad flag '--' used after filename" ]; do              
                                                                              
        err=$(git grep "$@" -- `git ls-files $moved | grep -iv "$EXCLUDES"` \  
            2>&1 1>&3-)                                                        
     3>&1                                                                     

    # The rest of the code in this loop is here to move the last argument in   
    # the arglist to a separate list $moved. I had issues with whitespace in   
    # the search-string, so this is loosely based on:                          
    #   http://www.linuxjournal.com/content/bash-preserving-whitespace-using-set-and-eval
    x=1                                                                        
    items=                                                                     
    for i in "$@"; do                                                          
        if [ $x -lt $# ]; then                                                 
            items="$items \"$i\""                                              
        else                                                                   
            moved="$i $moved"                                                  
        fi                                                                     
        x=$(($x+1))                                                            
    done                                                                       
    eval set -- $items                                                         
done                                                                           
# Show the error if there was any                                              
echo $err                                                                      

注 1

根据this 应该可以将事物命名为git-gg 并能够将其作为常规git 命令调用,例如:

$ git gg searchstring

但我无法让它工作。我在~/bin/ 中创建了脚本,并在/usr/lib/git-core/ 中创建了git-gg 符号链接。

注2

该命令不能成为常规的sh git-alias,因为它将在 repo 的根目录中调用。这不是我想要的!

【讨论】:

以上是关于如何从 git grep 搜索中排除某些目录/文件的主要内容,如果未能解决你的问题,请参考以下文章

如何从 git 中排除打字稿编译的文件

从 grep 中排除 .svn 目录 [重复]

如何在git repo中grep文件?

TFS 2015:如何排除某些文件夹触发使用 Git 构建

如何从 ack (ack-grep) 中排除特定文件?

使用 grep 进行文件搜索,不包括结果中的字段 [关闭]