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

<p>я удалил файл или некоторый код в файле когда-то в прошлом. могу ли я получить доступ к содержимому (а не к сообщениям о коммите)</p><p>очень плохим решением является поиск в журнале:</p><pre><code>git log -p | grep <pattern> </code></pre><p>однако это не сразу возвращает хеш коммита. я играл с <code>git grep</code> безрезультатно.</p>

<p>для поиска содержимого коммита <em> </em> (то есть фактических строк исходного текста, а не сообщений коммита и т. п.) вам необходимо сделать следующее:</p><pre><code>git grep <regexp> $(git rev-list --all) <strong>pdates</strong>: git rev-list --all | xargs git grep <expression> будет работать, если вы столкнетесь с ошибкой "список аргументов слишком длинный"если вы хотите ограничить поиск каким-либо поддеревом (например, "lib/util"), вам нужно будет передать его подкоманде rev-list и grep:git grep <regexp> $(git rev-list --all -- lib/util) -- lib/util </code></pre><p>это пролистает весь ваш текст коммита для регулярного выражения.</p><p>причина передачи пути в обеих командах состоит в том, что <code>rev-list</code> вернет список ревизий, в котором произошли все изменения в <code>lib/util</code>, но вам также нужно будет передать <code>grep</code>, чтобы он выполнял поиск только по <code>lib/util</code>.</p><p>просто представьте следующий сценарий: <code>grep</code> может найти тот же <code><regexp></code> в других файлах, которые содержатся в той же ревизии, возвращенной <code>rev-list</code> (даже если в этой ревизии не было изменений в этом файле).</p><p>вот несколько других полезных способов поиска вашего источника:</p><p>поиск рабочего дерева для текста, соответствующего регулярному выражению регулярное выражение:</p><pre><code>git grep <regexp> </code></pre><p>найдите в рабочем дереве строки текста, соответствующие регулярному выражению regexp1 или regexp2:</p><pre><code>git grep -e <regexp1> [--or] -e <regexp2> </code></pre><p>поиск в рабочем дереве строк текста, соответствующих регулярным выражениям regexp1 и regexp2, только пути к файлам отчетов:</p><pre><code>git grep -e <regexp1> --and -e <regexp2> </code></pre><p>найдите в рабочем дереве файлы, в которых строки текста соответствуют регулярному выражению regexp1, а строки текста соответствуют регулярному выражению regexp2:</p><pre><code>git grep -l --all-match -e <regexp1> -e <regexp2> </code></pre><p>поиск рабочего дерева по измененным строкам соответствия текста:</p><pre><code>git diff --unified=0 | grep <pattern> </code></pre><p>поиск всех ревизий для текста, соответствующего регулярному выражению regexp:</p><pre><code>git grep <regexp> $(git rev-list --all) поиск всех ревизий между rev1 и rev2 для текста, соответствующего регулярному выражению regexp:git grep <regexp> $(git rev-list <rev1>..<rev2>) </code></pre>

<p>вы должны использовать параметр <a href="https://git-scm.com/docs/git-log#git-log--sltstringgt">кирка (<code>-s</code>)</a> из <a href="http://git-scm.com/docs/git-log"><code>git log</code></a> </p><p>для поиска <code>foo</code>:</p><pre><code>git log -sfoo -- path\_containing\_change git log -sfoo --since=2009.1.1 --until=2010.1.1 -- path\_containing\_change </code></pre><p>смотрите <a href="https://stackoverflow.com/questions/2839253/git-history-find-lost-line-by-keyword/2839319#2839319">история git - найдите потерянную строку по ключевому слову</a> для получения дополнительной информации.</p><hr><p>как <a href="https://stackoverflow.com/users/46058/jakub-narebski">якуб наребски</a> прокомментировал:</p><ul> <li> <p>this <strong> ищет различия, которые вводят или удаляют экземпляр <code><string></code> </strong>.<br> обычно это означает "ревизии, в которых вы добавили или удалили строку с" foo "".</p> </li> <li> <p>опция <code>--pickaxe-regex</code> позволяет вам использовать расширенное регулярное выражение posix вместо поиска строки.</p> </li> </ul><hr><p>как прокомментировал <a href="https://stackoverflow.com/users/601626/rob">роб</a> , этот поиск чувствителен к регистру - он открыл <a href="https://stackoverflow.com/questions/25384842/case-insensitive-git-pickaxe-search">дополнительный вопрос</a> о том, как искать без учета регистра.</p>

<p>мой любимый способ сделать это с опцией <code>git log</code>'s <code>-g</code> (добавлен в версии 1.7.4).</p><pre><code>-g<regex> look for differences whose added or removed line matches the given <regex>. </code></pre><p>существует небольшая разница между тем, как параметры <code>-g</code> и <code>-s</code> определяют соответствие коммита:</p><ul> <li>опция <code>-s</code> по существу подсчитывает, сколько раз ваш поиск соответствует файлу до и после коммита. фиксация отображается в журнале, если значения до и после отличаются. это не будет, например, показывать коммиты, куда была перемещена строка, соответствующая вашему запросу.</li> <li>с параметром <code>-g</code> фиксация отображается в журнале, если ваш поиск соответствует какой-либо строке, которая была добавлена, удалена или изменена.</li> </ul><p>возьмите этот коммит в качестве примера:</p><pre><code>diff --git a/test b/test index dddc242..60a8ba6 100644 --- a/test +++ b/test @@ -1 +1 @@ -hello hello +hello goodbye hello </code></pre><p>поскольку число раз, когда "hello" появляется в файле, одинаково до и после этой фиксации, оно не будет совпадать при использовании <code>-shello</code>. однако, поскольку в строку, соответствующую <code>hello</code>, было внесено изменение, фиксация будет показана с использованием <code>-ghello</code>.</p>

<p>если вы хотите просмотреть изменения кода (посмотреть, что на самом деле изменилось с данным word во всей истории), перейдите в режим <code>patch</code> - я нашел очень полезную комбинацию выполнения:</p><pre><code>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 ;) ) </code></pre>

<p>я взял <a href="https://stackoverflow.com/questions/2928584/how-to-grep-in-the-git-history/2929502#2929502">ответ @ jeet</a> и добавил его в windows (спасибо <a href="https://stackoverflow.com/questions/434038/whats-the-cmd-powershell-equivalent-of-back-tick-on-bash/434087#434087">этот ответ</a> ):</p><pre><code>for /f %x in ('"git rev-list --all"') do @git grep <regex> %x > out.txt </code></pre><p>обратите внимание, что для меня, по какой-то причине, фактический коммит, который удалил это регулярное выражение, не появился в выходных данных команды, а скорее один коммит до него.</p>

<p><code>git log</code> может быть более эффективным способом поиска текста во всех ветвях, особенно если имеется много совпадений, и вы хотите сначала увидеть более свежие (релевантные) изменения.</p><pre><code>git log -p --all -s 'search string' git log -p --all -g 'match regular expression' </code></pre><p>эти комманды журнала регистрируют коммиты, которые добавляют или удаляют заданную строку поиска/регулярное выражение, (как правило) более новые в первую очередь. опция <code>-p</code> позволяет отображать соответствующий diff, где шаблон был добавлен или удален, так что вы можете увидеть его в контексте.</p><p>найдя соответствующий коммит, который добавляет текст, который вы искали (например, 8beeff00d), найдите ветки, которые содержат коммит:</p><pre><code>git branch -a --contains 8beeff00d </code></pre>

<p>поиск в <strong>любая ревизия, любые файлы</strong>:</p><pre><code>git rev-list --all | xargs git grep <regexp> </code></pre><p>поиск только в некоторых заданных файлах, для <strong>пример</strong> xml-файлов:</p><pre><code>git rev-list --all | xargs -i{} git grep <regexp> {} -- "*.xml" </code></pre><p>строки результата должны выглядеть следующим образом: 6988bec26b1503d45eb0b2e8a4364afb87dde7af: bla.xml: текст найденной строки ...</p><p>затем вы можете получить больше информации, например об авторе, дате, разнице, используя git show:</p><pre><code>git show 6988bec26b1503d45eb0b2e8a4364afb87dde7af </code></pre>

<p>для всех, кто пытается сделать это в <strong>sourcetree</strong>, в пользовательском интерфейсе для него нет прямой команды (начиная с версии 1.6.21.0). однако вы можете использовать команды, указанные в принятом ответе, открыв окно <strong>терминал</strong> (кнопка доступна на главной панели инструментов) и скопировав/вставив их в него.</p><p>примечание. представление sourcetree <strong>search</strong> может частично выполнять поиск текста для вас. нажмите <kbd>ctrl</kbd> + <kbd>3</kbd> чтобы перейти к представлению "поиск" (или нажмите вкладку "поиск" внизу). в крайнем правом углу установите тип поиска на <strong>file changes</strong>, а затем введите строку, которую хотите найти. этот метод имеет следующие ограничения по сравнению с приведенной выше командой:</p><ol> <li>sourcetree показывает только <em> коммиты </em>, которые содержат поисковое слово в одном из измененных файлов. поиск точного файла, который содержит текст для поиска, снова является ручной задачей.</li> <li>regex не поддерживается.</li> </ol>

<p>для простоты я бы предложил использовать графический интерфейс: <a href="https://git-scm.com/docs/gitk">gitk - браузер репозитория git</a> , он довольно гибкий</p><ol> <li>искать код: <a href="https://i.stack.imgur.com/3ymk8.png"><img src="https://i.stack.imgur.com/3ymk8.png" alt="enter image description here"></a> </li> <li>для поиска файла: <a href="https://i.stack.imgur.com/58qpa.png"><img src="https://i.stack.imgur.com/58qpa.png" alt="enter image description here"></a> </li> <li>конечно, он также поддерживает регулярное выражение: <a href="https://i.stack.imgur.com/u3tat.png"><img src="https://i.stack.imgur.com/u3tat.png" alt="enter image description here"></a> </li> </ol><p>и вы можете перемещаться по результатам, используя стрелки вверх/вниз</p>

<p>ответ @ jeet работает в powershell.</p><pre><code>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 "(^.?:)|(:.)", "" } 

итак, вы пытаетесь просмотреть старые версии кода, чтобы увидеть, где что-то существует в последний раз?если бы я делал это, я бы, вероятно, использовал <a href="http://www.kernel.org/pub/software/scm/git/docs/git-bisect.html">git bisect . используя bisect, вы можете указать известную хорошую версию, известную плохую версию и простой скрипт, который проверяет, является ли версия хорошей или плохой (в этом случае grep, чтобы увидеть, присутствует ли код, который вы ищете ). запуск этого найдет, когда код был удален.

git rev-list --all | xargs -n 5 git grep expression это решение для настройки @ jeet, поэтому оно показывает результаты во время поиска, а не только в конце (что может занять много времени в большом репо).

сценарий. вы тщательно очистили свой код с помощью ide. проблема: ide вылечил больше, чем нужно, и теперь ваш код не скомпилирован (отсутствуют ресурсы и т.д.)решение :git grep --cached "text_to_find"он найдет файл, в котором "text_to_find" был изменен.теперь вы можете отменить это изменение и скомпилировать свой код.

в моем случае мне нужно было найти short commit, и перечисленные решения, к сожалению, не работали.мне удалось сделать это с помощью: (заменить <strong>regex</strong> токен)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 </code></pre>