Как выполнить поиск по всем коммитам Git и Mercurial в хранилище для определенной строки?

287

У меня есть Git-репозиторий с несколькими ветками и висячими коммитами. Я хотел бы найти все такие коммиты в хранилище для конкретной строки.

Я знаю, как получить журнал всех коммитов в истории, но они не включают ветки или висячие капли, а только историю HEAD. Я хочу получить их все, чтобы найти конкретный коммит, который оказался неуместным.

Я также хотел бы знать, как сделать это в Mercurial, так как я рассматриваю переход.

Иосип
источник

Ответы:

331

Вы можете увидеть висячие коммиты с git log -g.

-g, --walk-reflogs
 Instead of walking the commit ancestry chain, walk reflog entries from
 the most recent one to older ones. 

Таким образом, вы можете сделать это, чтобы найти конкретную строку в сообщении коммита, которая висит:

git log -g --grep=search_for_this

В качестве альтернативы, если вы хотите найти изменения для определенной строки, вы можете использовать опцию поиска кирки "-S":

git log -g -Ssearch_for_this
# this also works but may be slower, it only shows text-added results
git grep search_for_this $(git log -g --pretty=format:%h)

Git 1.7.4 добавит опцию -G , позволяющую вам передать -G <regexp>, чтобы найти, когда была перемещена строка, содержащая <regexp>, что -S не может сделать. -S сообщит вам только об изменении общего числа строк, содержащих строку (т.е. добавление / удаление строки).

Наконец, вы можете использовать gitk для визуализации висячих коммитов:

gitk --all $(git log -g --pretty=format:%h)

А затем используйте его функции поиска, чтобы найти неуместный файл. Вся эта работа при условии, что отсутствующий коммит не «просрочен» и не был собран сборщиком мусора, что может произойти, если оно свисает в течение 30 дней и у вас истекают reflogs или запускается команда, срок действия которой истекает.

richq
источник
4
Возможно, вместо того, чтобы запускать «git grep» для (возможно, большого) числа коммитов, которые найдут все коммиты, которые имеют «search_for_this» где-то в проекте, используйте так называемый поиск «киркой», то есть опцию «-S» для git log , который находит коммиты, которые ввели или удалили данную строку, или, точнее, там, где изменилось число вхождений данной строки.
Якуб Наребски
5
Вы можете указать несколько веток или использовать опцию --all, например, 'git log --grep = "строка в сообщении коммита" --all'
Jakub Narębski
Это только позволило мне найти потерянный коммит за 2 дня работы. Полностью спас мою задницу, спасибо!
Майк Чемберлен
2
Я сталкивался с некоторыми ситуациями, когда у меня были коммиты в моей базе данных, но не в моем reflog. Я не знаю, насколько это распространено. Я пробовал разные мосты hg / git. Я думаю, что это также может возникнуть при сброшенных тайниках. В любом случае, этот псевдоним прекрасно работает, чтобы поймать эти случаи:!git fsck --unreachable | sed -ne 's/^unreachable commit //p' | xargs git log --no-walk
dubiousjim
Обратите внимание, что не включает поиск объектов заметки. Это еще не было реализовано: git.661346.n2.nabble.com/…
Энтони Стаббс
54

В Mercurial вы используете hg log --keywordдля поиска ключевых слов в сообщениях фиксации и hg log --userдля поиска конкретного пользователя. Смотрите hg help logдругие способы ограничения журнала.

Мартин Гайслер
источник
36
Йосип написал, что он рассматривает возможность перехода на Mercurial и что он также хотел бы услышать, как это делается там.
Мартин Гейслер
1
hg log -kпоиск фиксирует также имена пользователей и имена файлов в наборах изменений (я вижу это в command.py:log), что является одной из немногих вещей, которые я не понимаю в hg. Должны быть отдельные опции для поиска в сообщениях фиксации и именах файлов. Похоже, hg log --template '{desc}\n'|grepэто верный путь.
Джеффри Чжэн
@ GeoffreyZheng: есть способы сделать это. Смотрите "hg help revsets", esp функции desc (), user () и file (). Есть также переключатели журнала hg для большей части этого поведения. По моему опыту, хотя -k / keyword () обычно является наиболее полезным способом поиска вещей.
Кевин Хорн
Как можно выполнить поиск по фактическому фиксированному содержимому файла ... различия? Я знаю, что это будет медленный поиск, но я хочу сделать глубокий поиск отсутствующего имени функции.
Джонатан
О, вот оно:hg grep --all <term>
Джонатан
24

В дополнение к ответу richq об использовании git log -g --grep=<regexp>или git grep -e <regexp> $(git log -g --pretty=format:%h): взгляните на следующие посты в блоге Junio ​​C Hamano, текущего сопровождающего git


Резюме

И мерзавец Grep и мерзавец журнал --grep является линией ориентированного , в том , что они ищут линии , которые соответствуют заданным шаблону.

Вы можете использовать git log --grep=<foo> --grep=<bar>(или git log --author=<foo> --grep=<bar>это внутренне переводится на два --grep), чтобы найти коммиты, которые соответствуют любому из шаблонов (неявное ИЛИ семантическое).

Из - за того , чтобы быть линия-ориентированной, полезный и семантика использовать git log --all-match --grep=<foo> --grep=<bar>для поиска фиксации , которая имеет как соответствие строки первой и второй линии согласования где - то.

С git grepвы можете объединить несколько шаблонов (все , которые должны использовать -e <regexp>форму) с --or(это значение по умолчанию), --and, --not, (и ). Для grep --all-matchозначает, что файл должен иметь строки, соответствующие каждой из альтернатив.

Якуб Наребски
источник
Эй, Якуб, не возражаешь интегрировать цитаты / резюме из этих постов здесь? Похоже, один из винтажных ответов только для ссылок прямо сейчас.
Натан Тагги
11

Основываясь на ответе rq, я обнаружил, что эта строка делает то, что я хочу:

git grep "search for something" $(git log -g --pretty=format:%h -S"search for something")

Который сообщит идентификатор фиксации, имя файла и отобразит соответствующую строку, например:

91ba969:testFile:this is a test

... Кто-нибудь согласен, что это было бы хорошим вариантом для включения в стандартную команду git grep?

Сэм Хайатт
источник
5

Любая команда, которая принимает ссылки в качестве аргументов, примет --allопцию, задокументированную на странице man для git rev-listследующего:

   --all
       Pretend as if all the refs in $GIT_DIR/refs/ are listed on the
       command line as <commit>.

Так, например, git log -Sstring --allбудут отображаться все коммиты, которые упоминаются stringи которые доступны из ветки или из тега (я предполагаю, что ваши оборванные коммиты, по крайней мере, названы тегом).

адль
источник
3
По-видимому, это не относится к случаю git grep, когда --allпереводится на / используется как --all-match. Для меня это похоже на ошибку ... использование Git 1.7.2.3 (использование $(git rev-list --all)работ).
синеватый
5

С Mercurial вы делаете

$ hg grep "search for this" [file...]

Существуют и другие параметры, которые сужают диапазон проверяемых ревизий.

Yawar
источник
1
Мне также нравится флагhg grep --all
Джонатан
2

Не знаю насчет git, но в Mercurial я бы просто перенаправил вывод hg log в какой-нибудь скрипт sed / perl / what для поиска того, что вы ищете. Вы можете настроить вывод hg log, используя шаблон или стиль, чтобы облегчить поиск, если хотите.

Это будет включать все именованные ветви в репо. У Mercurial нет чего-то похожего на свисающие шарики afaik.

Курт Шелфтоут
источник
1
Я не понимаю, насколько этот ответ имеет отношение к указанной проблеме.
Jribeiro
3
Это ответ на вопрос для Mercurial, о котором первоначальный вопрос спрашивается в последнем абзаце.
Курт Шелфоут
1

Чтобы добавить еще одно решение, еще не упомянутое, я должен был сказать, что использование графического окна поиска gitg было самым простым решением для меня. Он выберет первое вхождение, и вы можете найти следующее с помощью Ctrl-G.

icarito
источник
1

Одна команда в git, которая, я думаю, намного проще найти строку:

git log --pretty=oneline --grep "string to search"

работает в Git 2.0.4

Адриано Роза
источник