Как исключить определенные каталоги/файлы из git grep search

Есть ли способ поиска репозитория git с помощью git grep, но исключить из поиска определенные пути/каталоги/файлы? Как и опция --exclude в обычной команде grep.

Если вам интересно: я не хочу использовать обычный grep, поскольку он намного медленнее, чем git grep, когда размер репозитория git большой.

Ответ 1

Это невозможно, но недавно обсуждалось. Предлагаемый обходной путь в ссылке:

Вы можете поместить *.dll в файл .gitignore, затем git grep --exclude-standard.

РЕДАКТИРОВАТЬ увидеть только один ответ, так как git 1.9.0 это возможно.

Ответ 2

В git pathspec exclude "волшебного слова" было добавлено в pathspec. Поэтому, если вы хотите искать foobar в каждом файле, кроме тех, которые соответствуют *.java вы можете сделать:

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

Или используя ! "короткая форма" для исключения:

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

Обратите внимание, что в версиях git до v2.12 при использовании pathspec исключений pathspec вас должен быть хотя бы один "включающий" pathspec. В приведенных выше примерах это ./* (рекурсивно включать все в текущем каталоге). В git v2.13 это ограничение было снято, и git grep foobar -- ':!*.java' работает без ./*.

Вы также можете использовать что-то вроде :(top) (краткая форма :/), чтобы включить все из верхней части репо. Но тогда вы, вероятно, также захотите настроить ваш исключающий pathspec к pathspec чтобы он начинался сверху:: :/!*.java (иначе он будет исключать только файлы *.java из вашего текущего каталога).

Есть хорошая ссылка на все "волшебные слова", разрешенные в pathspec на git-scm.com (или просто git help glossary). По какой-то причине документы на kernel.org действительно устарели, хотя они часто появляются первыми в поиске в Google.

Ответ 3

Обновление: Для git >= 1.9 существует встроенная поддержка шаблонов исключений, см. только один ответ.

Это может показаться обратным, но вы можете передать список файлов, не соответствующих вашему шаблону исключения, в git grep следующим образом:

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

grep -v возвращает каждый путь, не соответствующий <exclude-pattern>. Обратите внимание, что git ls-files также принимает параметр --exclude, но применяется только к файлам без следа.

Ответ 4

В примере с помощью @kynan в качестве базы я сделал этот script и поместил его в свой путь (~/bin/) как gg. Он использует git grep, но избегает определенных типов файлов.

В нашем репо было много изображений, поэтому я исключил файлы изображений, и это приведет к тому, что в течение всего времени репозитория будет отведено до 1/3 секунды. Но script можно легко изменить, чтобы исключить другие filestypes или 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 "[email protected]" -- `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 "[email protected]"; 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

Но я не могу заставить это работать. Я создал script в моем ~/bin/ и сделал символическую ссылку git-gg в /usr/lib/git-core/.

Примечание 2

Команда не может быть выполнена в обычный sh git -alias, так как она будет вызываться в корне репо. И это не то, что я хочу!

Ответ 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]