简体   繁体   中英

How to exclude certain directories/files from git grep search

Is there a way to exclude certain paths/directories/files when searching a git repository using git grep ? Something similar to the --exclude option in the normal grep command?

I need to use git grep because using grep directly runs too slowly on large git repositories.

In git 1.9.0 the "magic word" exclude was added to pathspec s. So if you want to search for foobar in every file except for those matching *.java you can do:

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

Or using the ! "short form" for exclude:

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

Note that in git versions up to v2.12, when using an exclude pathspec , you must have at least one "inclusive" pathspec . In the above examples this is the ./* (recursively include everything under the current directory). In git v2.13 this restriction was lifted and git grep foobar -- ':!*.java' works without the ./* .

You could also use something like :(top) (short form: :/ ) to include everything from the top of the repo. But then you'd probably also want to adjust your exclude pathspec to start from the top as well: :/!*.java (otherwise it would only exclude *.java files from under your current directory).

There's a good reference for all the "magic words" allowed in a pathspec at git-scm.com (or just git help glossary ). For some reason, the docs at kernel.org are really out of date even though they often come up first in google searches.

Update: For git >= 1.9 there is native support for exclude patterns, see onlyone's answer .

This may seem backwards, but you can pass a list of files not matching your exclude pattern to git grep like this:

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

grep -v returns every path not matching <exclude-pattern> . Note that git ls-files also takes a --exclude parameter, but that is only applied to untracked files .

It's not possible, but has been discussed recently . Proposed workaround in link:

You can put *.dll to .gitignore file then git grep --exclude-standard .

EDIT see onlynone's answer , since git 1.9.0 it's possible.

You can mark files or directories as binary by creating an attributes file in your repository, eg

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

Matches in binary files are listed without the including line, eg

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

With the example by @kynan as base I made this script and put it in my path ( ~/bin/ ) as gg . It does use git grep but avoids some specified filetypes.

In our repo its a lot of images so I have excluded the imagefiles, and this takes the serchtime down to 1/3 if I search the whole repo. But the script could easily be modified to exclude other filestypes or 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                                                                      

Note 1

According to this it should be possible to name the thing git-gg and be able to call it as a regular git command like:

$ git gg searchstring

But I can not get this working. I created the script in my ~/bin/ and made a the git-gg symlink in /usr/lib/git-core/ .

Note 2

The command can not be made into an regular sh git-alias since it will then be invoked at the root of the repo. And that is not what I want!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM