Как выполнить поиск (поиск) зафиксированного кода в истории Git?

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

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

git log -p | grep <pattern>

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

Ответ 1

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

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

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

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

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

Это пролистает весь ваш текст коммита для regexp.

Причина передачи пути в обеих командах состоит в том, что 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>)

Ответ 2

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


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

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

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


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

Ответ 3

Мой любимый способ сделать это с помощью опции git log -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

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

Ответ 4

Если вы хотите просмотреть изменения кода (см., что на самом деле было изменено с данным словом за всю историю), перейдите в режим 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 ;) )

Ответ 5

Я взял @Jeet answer и применил его к Windows (благодаря этому ответу):

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

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

Ответ 6

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

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

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

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

git branch -a --contains 8beeff00d

Ответ 7

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

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

Ответ 8

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

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

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

Ответ 9

Для простоты я бы предложил использовать GUI: gitk - Браузер репозитория Git. Это довольно гибкий

  1. Для поиска кода:

    Enter image description here
  2. Для поиска файлов:

    Enter image description here
  3. Конечно, он также поддерживает регулярные выражения:

    Enter image description here

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

Ответ 10

@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 "(^.*?:)|(:.*)", "" }

Ответ 11

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

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

Ответ 12

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

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

Ответ 13

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

Решение:

git grep --cached "text_to_find"

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

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

Ответ 14

Всякий раз, когда я нахожусь на вашем месте. Я использую следующую командную строку:

git log -S "<words/phrases i am trying to find>" --all --oneline  --graph 

Объяснение:

  1. git log - Нужно ли мне писать больше здесь, он показывает журналы в хронологическом порядке.
  2. -S "<words/phrases i am trying to find>" - показывает все те git-коммиты, где в любом файле (добавлен/изменен/удален) есть слова/фразы, которые я пытаюсь найти без символов '& lt;>'.
  3. --all - Для обеспечения и поиска по всем ветвям.
  4. --oneline - он сжимает журнал git в одну строку.
  5. --graph - Создает график хронологически упорядоченных коммитов.

Ответ 15

В моем случае мне нужно было искать 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