Можно ли выполнить «поиск по grep» во всех ветках проекта Git?

138

Можно ли запустить git grepвсе ветки проекта Git? Или есть другая команда для запуска?

epsilones
источник
4
Возможный дубликат Использование git, как я могу найти строку во всех ветвях?
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功

Ответы:

189

На вопрос « Как выполнить поиск (поиск) зафиксированного кода в истории git? » Рекомендуется:

 git grep <regexp> $(git rev-list --all)

Он просматривает все коммиты, которые должны включать все ветви.

Другая форма будет:

git rev-list --all | (
    while read revision; do
        git grep -F 'yourWord' $revision
    done
)

Вы можете найти еще больше примеров в этой статье :

Я попробовал описанное выше на одном достаточно большом проекте, чтобы git пожаловался на размер аргумента, поэтому, если вы столкнетесь с этой проблемой, сделайте что-то вроде:

git rev-list --all | (while read rev; do git grep -e <regexp> $rev; done)

(см. альтернативу в последнем разделе этого ответа ниже)

Не забудьте эти настройки, если вы хотите их:

# Allow Extended Regular Expressions
git config --global grep.extendRegexp true
# Always Include Line Numbers
git config --global grep.lineNumber true

Этот псевдоним тоже может помочь:

git config --global alias.g "grep --break --heading --line-number"

Примечание: Черни предположил, что git rev-list --allэто излишество.

Более точная команда может быть:

git branch -a | tr -d \* | xargs git grep <regexp>

Который позволит вам искать только филиалы (включая удаленные филиалы)

Вы можете даже создать псевдоним bash / zsh для него:

alias grep_all="git branch -a | tr -d \* | xargs git grep"
grep_all <regexp>

Обновление август 2016: RM рекомендует в комментариях

Я получил " fatal: bad flag '->' used after filename" при попытке git branchверсии. Ошибка была связана с HEADобозначением псевдонимов.

Я решил это, добавив sed '/->/d'в трубу, между trи xargsкомандами.

 git branch -a | tr -d \* | sed '/->/d' | xargs git grep <regexp>

То есть:

alias grep_all="git branch -a | tr -d \* | sed '/->/d' | xargs git grep"
grep_all <regexp>
VonC
источник
Не очень хорошая идея передавать результаты git branchв tr или sed; git branchэто фарфоровая команда, предназначенная для потребления человеком. См. Stackoverflow.com/a/3847586/2562319 для предпочтительных альтернатив.
Jbyler
@jbyler Хорошая мысль. По иронии судьбы я опубликовал ответ на фарфоре задолго до этого ответа: stackoverflow.com/a/6978402/6309 . И я использую его, например, в stackoverflow.com/a/19206916/6309 .
VonC
Да, хорошо. Просматривая другие ответы, я думаю, что ответ @errordeveloper - самый чистый: stackoverflow.com/a/21284342/2562319 : "git grep <regexp> $ (git for-each-ref --format = '% (refname) 'refs /) "
jbyler
1
Есть ли способ показать название ветки, которая соответствовала поиску?
Франкс
63

git log может быть более эффективным способом поиска текста во всех ветвях, особенно если имеется много совпадений, и вы хотите сначала увидеть более свежие (релевантные) изменения.

git log -p --all -S 'search string'
git log -p --all -G 'match regular expression'

Эти комманды журнала регистрируют коммиты, которые добавляют или удаляют заданную строку поиска / регулярное выражение, (как правило) более новые в первую очередь. -pОпция вызывает соответствующий дифференциал будет показан , где была добавлена или удалена картина, так что вы можете увидеть его в контексте.

Найдя соответствующий коммит, который добавляет текст, который вы искали (например, 8beeff00d), найдите ветки, которые содержат коммит:

git branch -a --contains 8beeff00d
Эдвард Андерсон
источник
22

Я нашел это наиболее полезным:

git grep -i foo `git for-each-ref --format='%(refname)' refs/`

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

  • git grep -i foo $(git for-each-ref --format='%(refname)' refs/remotes)
  • git grep -i foo $(git for-each-ref --format='%(refname)' refs/heads)

Псевдоним, который я создал, выглядит следующим образом:

grep-refs = !sh -c 'git grep "$0" "$@" "$(git for-each-ref --format=\"%(refname)\"" refs/)'
errordeveloper
источник
1
Интересный псевдоним. +1. Точнее, чем в моем ответе.
VonC
Как заставить ваш псевдоним работать для поиска по фразе? Когда я передаю «foo bar» в качестве параметра, я получаю: fatal: неоднозначный аргумент «bar»: неизвестная ревизия или путь вне рабочего дерева. Используйте '-', чтобы отделить пути от ревизий
jutky
Попробуйте убежать от места: "foo \ bar"
Гарри Гомес
Ясно, что это будет принятый ответ;) Я расширил его для поиска только по последним ветвям моего проекта (получил более 500, не спрашивайте, и каждый grep занимает около 4 секунд, поэтому я не хочу и не нужен искать более чем, скажем, 100 последних из них). Для этого я обновил git for-each-refс --sort=-committerdate --count=100! Спасибо за оригинальную идею!
Вс
6

Это можно сделать двумя способами: псевдонимы Bash или Git.

Вот три команды:

  1. git grep-branch - Поиск во всех филиалах локальных и удаленных
  2. git grep-branch-local - Искать только в местных филиалах
  3. git grep-branch-remote - только удаленные филиалы

Использование такое же, как git grep

git grep-branch "find my text"
git grep-branch --some-grep-options "find my text"

Использование GREP: Git aliases

Файл ~ / .gitconfig

Команды должны быть добавлены в ~/.gitconfigфайл вручную , потому что вы git config --global aliasоцениваете сложный код и вносите в него ошибки


[alias]
    grep-branch        = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' | xargs git grep $@; };f "
    grep-branch-remote = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' | grep '^remotes' | xargs git grep $@; };f"
    grep-branch-local  = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' -e '^remotes' | xargs git grep $@;  };f "

Примечание. Когда вы добавляете псевдонимы, но они не запускаются - проверьте обратную косую черту, для \них может потребоваться дополнительный экранирование \\по сравнению с командами bash .

  • git branch -a - отображать все ветки;
  • sed -e 's/[ \\*]*//'- пробелы (от branch -a) и * (у активного имени ветви есть);
  • grep -v -e '\\->'- игнорировать сложные имена, как remotes/origin/HEAD -> origin/master;
  • grep '^remotes' - Получить все удаленные филиалы;
  • grep -v -e '^remotes'- получать ветки кроме удаленных веток;

пример git grep-branch-local -n getTastyCookies

-n Префикс номера строки соответствует строке.

[user@pc project]$ git grep-branch-local -n getTastyCookies

dev:53:modules/factory/getters.php:function getTastyCookies($user);
master:50:modules/factory/getters.php:function getTastyCookies($user)

Текущая структура:

: - Разделитель

  1. Филиал: dev
  2. Номер строки: 53
  3. Путь файла: modules/factory/getters.php
  4. Соответствующая линия: function getTastyCookies($user)

Использование GREP: BASH

Как вы должны знать: команды Bash должны храниться в .shскриптах или запускаться в оболочке.

Только местные филиалы

git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' -e '^remotes' | xargs git grep "TEXT"

Только удаленные филиалы

git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' | grep '^remotes' | xargs git grep "TEXT"

Локальные и удаленные филиалы

git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' | xargs git grep "TEXT"
Devaldo
источник
Звучит хорошо, но я получил эту ошибку от git grep-branch "find my text":fatal: ambiguous argument 'client': both revision and filename
nealmcb
Почему всегда использовать -a, который показывает все ветви? Я бы предложил использовать опции git branchкоманды для разделения веток. При взгляде на местные филиалы, есть только один *, так что нет необходимости избегать его для sed. Итак: только git branch | sed -e 's/*/ /' | xargs git grep "TEXT"для локальных филиалов, только git branch -r | grep -v -- "->" | xargs git grep "TEXT"для удаленных филиалов и git branch -a | grep -v -- "->" | xargs git grep "TEXT"для всех филиалов
jalanb
4

Вот как я это делаю:

git for-each-ref --format='%(*refname)' | xargs git grep SEARCHTERM
Уильям Энтрикен
источник
2
Единственное решение, которое работало для меня на Windows (в Git Bash)
Иван
4

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

Чтобы найти все ветви, вы можете получить все деревья с git rev-list --all. Поместите все это с

git grep "regexp" $(git rev-list --all)

... и иметь терпение

CharlesB
источник