it-swarm-ru.tech

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

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

Очень плохим решением является поиск в журнале:

git log -p | grep <pattern>

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

1266
Ortwin Gentz

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

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

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

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

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

Это пролистает весь ваш текст коммита для регулярного выражения.

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

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

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

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

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>)
1684
Jeet

Вы должны использовать параметр кирка (-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 - найдите потерянную строку по ключевому слову для получения дополнительной информации.


Как Якуб Наребски прокомментировал:

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

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


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

480
VonC

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

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

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

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

Возьмите этот коммит в качестве примера:

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.

225
Tyler Holien

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

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 ;) )
44
Bartek Skwira

Я взял ответ @ Jeet и добавил его в Windows (спасибо этот ответ ):

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

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

24
ripper234

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

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

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

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

git branch -a --contains 8beeff00d
19
Edward Anderson

Поиск в любая ревизия, любые файлы:

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
17
Christophe Roussy

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

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

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

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

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

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

5
watashiSHUN

Ответ @ 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 "(^.*?:)|(:.*)", "" }
2
Shaun Luttin

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

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

2
Rob Di Marco
git rev-list --all | xargs -n 5 git grep EXPRESSION

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

1
laktak

Сценарий. Вы тщательно очистили свой код с помощью IDE. Проблема: IDE вылечил больше, чем нужно, и теперь ваш код не скомпилирован (отсутствуют ресурсы и т.д.)

Решение :

git grep --cached "text_to_find"

Он найдет файл, в котором "text_to_find" был изменен.

Теперь вы можете отменить это изменение и скомпилировать свой код.

1
Garytech

В моем случае мне нужно было найти Short Commit, и перечисленные решения, к сожалению, не работали.

Мне удалось сделать это с помощью: (заменить 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
0
user1183098