Як виключити певні каталоги / файли з пошуку git grep


144

Чи є спосіб виключити певні шляхи / каталоги / файли під час пошуку сховища git за допомогою git grep? Щось подібне до --excludeпараметра в звичайній grepкоманді?

Мені потрібно користуватися, git grepоскільки використання grepбезпосередньо працює надто повільно на великих сховищах git.


Робити це на баш буде можливий обхідний шлях: stackoverflow.com/questions/216995 / ...
Чіро Сантіллі郝海东冠状病六四事件法轮功

8
Ця функція була додана в 1.9.0. Див. Мою відповідь нижче
onlynone

Відповіді:


17

Це неможливо, але обговорювалося недавно . Пропоноване вирішення за посиланням:

Ви можете помістити *.dllфайл .gitignore тоді git grep --exclude-standard.

EDIT дивіться відповідь onlynone , оскільки git 1.9.0 це можливо.


2
Це раніше було правдою, але вже не, тепер це можливо в git. Подивіться , що має бути реальний відповідь нижче: stackoverflow.com/a/30084612/1391445
user1391445

206

У git 1.9.0 до " s " excludeбуло додано "магічне слово" pathspec. Отже, якщо ви хочете шукати foobarу кожному файлі, крім відповідних, *.javaви можете зробити:

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

Або використовуючи !"коротку форму" для виключення:

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

Зауважте, що у версіях git до v2.12 при використанні виключення pathspecви повинні мати принаймні один "включно" 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/**'щоб виключити кілька цілих каталогів. Я не думаю, що це перешкоджає рекурсії.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

2
Для частого використання, ви можете зробити GIT псевдонім з винятками: git config alias.mygrep '!git grep "$@" -- "${GIT_PREFIX}/*" ":!*.java*" #'. Тоді просто git mygrep foobar. (Використовуючи псевдонім оболонки # трюк та поточний реж .)
medmunds

Проблема, яку я не можу вирішити за допомогою цього рішення, полягає в тому, що повідомлені контури файлів відносяться до кореня WC. Отже, якщо я перебуваю в підпорядкуванні туалету, я не можу просто використовувати шлях знайденого файлу (-ів) таким, який є (наприклад, для меншої кількості), але мені доведеться з'єднувати загальні шляхи. Чи є для цього рішення (без необхідності спокійно сісти)? [git bash on win7]
elonderin

1
@elonderin це рішення не має нічого спільного з тим, як повідомляються відповідні файли. Але я просто спробував git grepі git ls-filesз підкаталогів, і з обох файлів звітів відносно поточного каталогу (навіть коли ви використовуєте ':(top)'include pathspec). Обидві команди мають --full-nameможливість повідомляти імена відносно кореня, але це за замовчуванням вимкнено.
onlynone

1
Я не використовую псевдоніми git, тому я зробив функцію bash, але, можливо, псевдонім git краще gist.github.com/cmdcolin/04e2378b60f4457a41904c659368066f
Колін D

62

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

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

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

grep -vповертає кожен шлях, який не відповідає <exclude-pattern>. Зверніть увагу, що git ls-filesтакож приймає --excludeпараметр, але він застосовується лише до файлів, що не відслідковуються .


Дякую за це! Git grep - це набагато швидше, ніж ack & co, але неможливість виключити довільні шляхи було занадто незручно, так би мовити :)
Tomasz Zieliński

2
На жаль, у мого репо є багато файлів. Коли я намагаюся підходити до @ kynan, я отримую: "-bash: / usr / bin / git: Аргумент занадто довгий"
Benissimo

2
Це повинно вирішити як проблему Бенісімо, як "Список аргументів занадто довгий", так і мою проблему з функціями caracters імені файлів, інтерпретованими bash (як []), або назви файлів, що містять пробіли у сховищі: git ls-files | grep -v <exclue-pattern> | xargs -d '\ n' git grep <pattern> -
Розвідник

2
Перевірте відповідь onlynone, можливо, це робити повністю цілком (в сучасних версіях) git зараз.
Девід

Чому голоси? Ця відповідь все ще стосується версій git до 1.9. Я додав замітку, що стосується лише відповіді однієї людини.
кинан

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, якщо я шукаю цілий репо. Але скрипт можна легко змінити, щоб виключити інші типи файлів або гелералематичні шаблони.

#!/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

Команду не можна перетворити на звичайний shпсевдонім git, оскільки вона буде викликана в корені репо. І це не те, що я хочу!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.