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

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

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

5 ответов

Решение

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

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

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

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

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

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

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

Обратите внимание, что при использовании исключения pathspecу вас должен быть хотя бы один "включительно" pathspec, В приведенных выше примерах это ./* (рекурсивно включать все в текущем каталоге).

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

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

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

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

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

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

Вы можете пометить файлы или каталоги как двоичные, создав файл атрибутов в вашем хранилище, например

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

На примере @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://stackru.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

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

Другие вопросы по тегам