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


144

使用搜寻git储存库时,是否有一种方法可以排除某些路径/目录/文件git grep?与--exclude正常grep命令中的选项相似吗?

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



8
此功能是在1.9.0版中添加的,请参见下面的答案

Answers:



204

在git 1.9.0中,“魔术词” exclude已添加到pathspecs中。因此,如果要foobar在除匹配文件之外的所有文件中进行搜索,*.java可以执行以下操作:

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

或使用!“简短形式”排除:

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

请注意,在v2.12之前的git版本中,使用exclude时pathspec,必须至少具有一个“ inclusive” pathspec。在上面的示例中,这是./*(递归包括当前目录下的所有内容)。在git v2.13中,取消了此限制,并且git grep foobar -- ':!*.java'无需使用即可./*

您还可以使用类似:(top)(简短格式:/:)的东西来包含仓库中的所有内容。但是随后您可能还希望将排除对象pathspec也从顶部开始进行调整:(:/!*.java否则,它将仅排除*.java当前目录下的文件)。

有在一个允许所有的“咒语”一个很好的参考pathspec,在git-scm.com(或只git help glossary)。由于某些原因,kernel.org上的文档实际上已经过时了,即使它们通常在Google搜索中排在首位。


4
git grep clock.gettime -- './*' ':!arch/**' ':!drivers/**'排除多个整个目录。我认为这不会阻止递归。
西罗Santilli郝海东冠状病六四事件法轮功2016年

2
为了经常使用,您可以使用以下排除项制作git别名:git config alias.mygrep '!git grep "$@" -- "${GIT_PREFIX}/*" ":!*.java*" #'。然后就git mygrep foobar。(使用别名shell#技巧当前目录。)
medmunds

我无法用此解决方案解决的问题是,文件的报告路径是相对于WC根目录的。因此,如果我在WC的子目录中,则不能按原样使用找到的文件的路径(例如,花更少的钱),而必须丢弃公共路径。有没有解决的办法(不需要强迫自己)?[win7上的git bash]
elonderin

1
@elonderin此解决方案与报告匹配文件的方式无关。但是我只是尝试了a git grepgit ls-filesfrom子目录,并且两个报告的文件名都相对于当前目录(即使使用':(top)'include pathspec时)。这两个命令都--full-name可以报​​告相对于根的名称,但默认情况下处于关闭状态。
onlynone

1
我不使用git别名,所以我做了一个bash函数,但是git别名可能更好gist.github.com/cmdcolin/04e2378b60f4457a41904c659368066f
Colin D

62

更新:对于git> = 1.9,本机支持排除模式,请参见onlyone的答案

这似乎向后看,但是您可以传递与您的排除模式不匹配的文件列表,git grep如下所示:

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

grep -v返回匹配的所有路径<exclude-pattern>。请注意,这git ls-files也需要一个--exclude参数,但这仅适用于未跟踪的文件


谢谢你!Git grep比ack&co快得多,但是不能排除任意路径有点麻烦:)
TomaszZieliński2013年

2
不幸的是,我的仓库有很多文件。当我尝试@kynan的方法时,我得到:“ -bash:/ usr / bin / git:参数列表太长”
Benissimo 2014年

2
这应该可以解决Benissimo的“参数列表太长”问题,也可以解决由bash解释的文件名字符(如[])或存储库中包含空格的文件名的问题:git ls-files | grep -v <exclue-pattern> | xargs -d'\ n'git grep <pattern>
Scout

2
检查onlynone的答案,现在可能完全在git(现代版本)中完成此操作。
David

为什么要下票?这个答案仍然适用于1.9之前的git版本。我添加了一条注释,仅提及一个人的答案。
kynan 2015年

5

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

$ 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]

2

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

在我们的仓库中有很多图像,因此我排除了图像文件,如果我搜索整个仓库,则将时间缩短到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://stackoverflow.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

根据这个应该可以说出的东西git-gg,并能称其为像一个普通的git命令:

$ git gg searchstring

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

笔记2

该命令不能设为常规的shgit-alias,因为它将在存储库的根目录中被调用。那不是我想要的!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.