Как grep (поиск) зафиксированный код в истории git?

Я удалил файл или какой-то код в файл когда-то в прошлом. Могу ли я grep в содержимом (не в сообщениях фиксации)?

очень плохое решение-grep журнал:

git log -p | grep <pattern>

однако это не возвращает хэш фиксации сразу. Я играл с git grep безрезультатно.

13 ответов


для поиска фиксации контент (т. е. фактические строки источника, в отличие от сообщений фиксации и тому подобного), что вам нужно сделать:

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

обновления: git rev-list --all | xargs git grep expression будет работать, если вы столкнетесь с ошибкой "список аргументов слишком длинный"

если вы хотите ограничить поиск некоторым поддеревом (например, "lib/util"), вам нужно будет передать это в rev-list команда и grep а также:

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

это будет grep через весь ваш текст фиксации для regexp.

причина прохождения пути в обеих командах заключается в том, что rev-list вернет список ревизий, где все изменения в lib/util случилось, но и вам нужно перейти к grep, так что он будет искать только на lib/util.

представьте себе следующий сценарий:grep может найти то же самое <regexp> на другие файлы, которые содержатся в той же редакции, возвращенной rev-list (даже если не было никаких изменений файл на эту ревизию).

вот некоторые другие полезные способы поиска источника:

поиск рабочего дерева для текста, соответствующего регулярному выражению regexp:

git grep <regexp>

поиск в рабочем дереве строк текста, соответствующих регулярному выражению regexp1 или regexp2:

git grep -e <regexp1> [--or] -e <regexp2>

поиск рабочего дерева для строк текста, соответствующих регулярному выражению regexp1 и regexp2, только пути к файлам отчетов:

git grep -e <regexp1> --and -e <regexp2>

поиск рабочего дерева для файлы, имеющие строки текста, соответствующие регулярному выражению regexp1 и строки текста, соответствующие регулярному выражению regexp2:

git grep -l --all-match -e <regexp1> -e <regexp2>

поиск рабочего дерева для измененных строк текста по шаблону:

git diff --unified=0 | grep <pattern>

поиск всех редакций для текста, соответствующего регулярному выражению regexp:

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

поиск всех ревизий между rev1 и rev2 для текста, соответствующего регулярному выражению regexp:

git grep <regexp> $(git rev-list <rev1>..<rev2>)

вы должны использовать Кирка (-S) на git log

искать Foo:

git log -SFoo -- path_containing_change 
git log -SFoo --since=2009.1.1 --until=2010.1.1 -- path_containing_change

посмотреть история Git-найти потерянную строку по ключевому слову дополнительные.


As Якуб Narębski комментирует:

  • этой ищет различия, которые вводят или удаляют экземпляр <string>.
    Обычно это означает " изменения, в которые вы добавили или удалена строка с 'Foo'".

  • на --pickaxe-regex опция позволяет использовать расширенное регулярное выражение POSIX вместо поиска строки.


As Роб прокомментировал, что этот поиск чувствителен к регистру - он открыл вопрос о том, как искать без учета регистра.


мой любимый способ сделать это с git log ' s (добавлена в версии 1.7.4).

-G<regex>
       Look for differences whose added or removed line matches the given <regex>.

существует тонкая разница между тем, как -G и -S параметры определяют, соответствует ли фиксация:

  • на -S опция по существу подсчитывает количество совпадений поиска в файле до и после фиксации. Фиксация отображается в журнале, если количество до и после отличается. Это не будет, например, показывать коммиты где была перемещена строка, соответствующая вашему поиску.
  • С , фиксация в журнале, Если ваш поиск соответствует любой строке, которая была добавлена, удалена или изменена.

возьмите эту фиксацию в качестве примера:

diff --git a/test b/test
index dddc242..60a8ba6 100644
--- a/test
+++ b/test
@@ -1 +1 @@
-hello hello
+hello goodbye hello

поскольку количество раз, когда" hello " появляется в файле, одинаково до и после этой фиксации, оно не будет совпадать с использованием -Shello. Однако, поскольку произошло изменение строки, соответствующей hello, фиксация будет показана используя -Ghello.


Если вы хотите просмотреть изменения кода (см., что на самом деле было изменено с данным словом во всей истории), перейдите к patch mode - я нашел очень полезную комбинацию действий:

git log -p
# hit '/' for search mode
# type in the word you are searching
# if the first search is not relevant hit 'n' for next (like in vim ;) )

взял @Джит-х и по мере ее Windows (спасибо ответ):

FOR /F %x IN ('"git rev-list --all"') DO @git grep <regex> %x > out.txt

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


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

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

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

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

git branch -a --contains 8beeff00d

поиска любая редакция, любые файлы:

git rev-list --all | xargs git grep <regexp>

поиск только в некоторых заданных файлах, например xml-файлах:

git rev-list --all | xargs -I{} git grep <regexp> {} -- "*.xml"

строки результатов должны выглядеть следующим образом: 6988bec26b1503d45eb0b2e8a4364afb87dde7af: bla.xml: текст найденной строки...

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

git show 6988bec26b1503d45eb0b2e8a4364afb87dde7af

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

Примечание: конечно же Поиск view может частично выполнять текстовый поиск для вас. Нажмите Ctrl + 3 перейти к просмотру поиска (или нажать вкладку "Поиск" внизу). В крайнем правом углу Установите тип поиска в Изменения Файла и затем введите строку, которую вы хотите найти. Этот метод имеет следующие ограничения по сравнению с приведенной выше командой:

  1. SourceTree показывает только commits, которые содержат искомое слово в одном из измененных файлов. Поиск точного файла, содержащего текст поиска, снова является ручной задачей.
  2. регулярное выражение не поддерживаемый.

для простоты я бы предложил использовать GUI:gitk-браузер репозитория Git, его довольно гибким

  1. в поиск код: enter image description here
  2. поиск файлов: enter image description here
  3. потому что он также поддерживает регулярные выражения: enter image description here

и вы можете перемещаться по результатам, используя стрелку вверх/вниз


Итак, вы пытаетесь grep через более старые версии кода, чтобы увидеть, где что-то последнее существует?

Если бы я это делал, я бы, вероятно, использовал git bisect. Используя bisect, вы можете указать известную хорошую версию, известную плохую версию и простой скрипт, который проверяет, является ли версия хорошей или плохой (в этом случае grep, чтобы увидеть, присутствует ли код, который вы ищете). Запуск этого найдет, когда код был удален.


ответ@Jeet работает в PowerShell.

git grep -n <regex> $(git rev-list --all)

ниже отображаются все файлы, в любом фиксации, которые содержат password.

# store intermediate result
$result = git grep -n "password" $(git rev-list --all)

# display unique file names
$result | select -unique { $_ -replace "(^.*?:)|(:.*)", "" }

git rev-list --all | xargs -n 5 git grep EXPRESSION

- это настройка решения @Jeet, поэтому он показывает результаты во время поиска, а не только в конце (что может занять много времени в большом РЕПО).


в моем случае мне нужно было найти короткую фиксацию, и перечисленные решения, к сожалению, не работали.

мне удалось сделать это с: (замените REGEX маркер)

for commit in $(git rev-list --all --abbrev-commit)
do
    if [[ $commit =~ __REGEX__ ]]; then 
        git --no-pager show -s --format='%h %an - %s' $commit
    fi
done