Как найти коммит Git, который ввел строку в любую ветку?


396

Я хочу быть в состоянии найти определенную строку, которая была введена в любой коммит в любой ветке, как я могу это сделать? Я нашел что-то (что я модифицировал для Win32), но git whatchanged, похоже, не смотрит на разные ветки (игнорируйте кусок py3k, это просто исправление перевода строки msys / win)

git whatchanged -- <file> | \
grep "^commit " | \
python -c "exec(\"import sys,msvcrt,os\nmsvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)\nfor l in sys.stdin: print(l.split()[1])\")" | \
xargs -i% git show origin % -- <file>

Неважно, если ваше решение медленное.


Ответы:


686

Ты можешь сделать:

git log -S <whatever> --source --all

Чтобы найти все коммиты, которые добавили или удалили фиксированную строку whatever . В --allозначает параметр , чтобы начать с каждой ветви и --sourceсредств , чтобы показать , какие из этих ветвей привели к обнаружению того, что фиксации. Часто полезно добавить, -pчтобы показать патчи, которые будут представлены также каждым из этих коммитов.

Версии git начиная с 1.7.4 также имеют похожую -Gопцию, которая принимает регулярное выражение . Это на самом деле имеет различные (и гораздо более очевидные) семантики, поясняется в этом блоге от Джунио Хамано .

Как отмечает thameera в комментариях, вам нужно ставить кавычки вокруг поискового запроса, если он содержит пробелы или другие специальные символы, например:

git log -S 'hello world' --source --all
git log -S "dude, where's my car?" --source --all

Вот пример использования, -Gчтобы найти вхождения function foo() {:

git log -G "^(\s)*function foo[(][)](\s)*{$" --source --all

19
+1 за превосходство. Указывать на -S - это одно, объяснять лучше. Кроме того, мне нравится использовать --decorate, чтобы увидеть, из каких ветвей происходят вещи
сэх

7
@sehe: Спасибо за ваш хороший комментарий. Полагаю, стоит отметить, что к --decorateкоммиту добавляется только имя ветки в конце каждой ветки. На практике я не использовать --sourceили --decorate, и вместо того, чтобы использовать , git branch -a --contains <commit-hash>чтобы найти , какие ветви содержит коммит меня интересует.
Марк Longair

3
добавьте -p, чтобы увидеть также встроенный diff, FWIW
rogerdpack

1
@MarkLongair не показывает изменения, сделанные при слиянии. Любое предложение, чтобы показать их, а?
Пахлеви Фикри Аулия

2
Для меня это работает , только если я удалить пространство между -S и поисковым термином, то есть git log -S"dude, where's my car?" --source --all. @ribamar также написал это в ответе ниже, но его легко можно пропустить рядом с этим топовым ответом.
bug313


20

Ответ Марка Лонгаира превосходен, но я нашел эту более простую версию для меня.

git log -S whatever

24
Просто чтобы прояснить, это работает нормально, если коммит, в котором вы ищете, находится HEAD, но этот конкретный вопрос задан специально о просмотре всех веток в репозитории.
Марк Лонгэйр

18

Возиться с такими же ответами:

$ git config --global alias.find '!git log --color -p -S '
  • ! необходимо, потому что иначе git не передает аргумент правильно -S. Смотрите этот ответ
  • --color и -p помогают точно показать "что изменилось"

Теперь вы можете сделать

$ git find <whatever>

или

$ git find <whatever> --all
$ git find <whatever> master develop

6
git log -S"string_to_search" # options like --source --reverse --all etc

Обратите внимание, чтобы не использовать пробелы между S и "string_to_search". В некоторых установках (git 1.7.1) вы получите ошибку вроде:

fatal: ambiguous argument 'string_to_search': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions

2

Хотя это не дает прямого ответа на ваш вопрос, я думаю, что это может быть хорошим решением для вас в будущем. Я видел часть моего кода, что было плохо. Не знал, кто это написал и когда. Я мог видеть все изменения из файла, но было ясно, что код был перемещен из какого-то другого файла в этот. Я хотел найти, кто на самом деле добавил это в первую очередь.

Для этого я использовал Git bisect , который быстро позволил мне найти грешника.

Я побежал, git bisect startа затем git bisect bad, потому что проверенная ревизия имела проблему. Так как я не знаю , когда возникла проблема, я целенаправленные первым совершить на «хорошо», git bisect good <initial sha>.

Тогда я просто продолжал искать в репозитории плохой код. Когда я его нашел, я побежал git bisect bad, а когда его там не было git bisect good.

В ~ 11 шагов я рассмотрел ~ 1000 коммитов и нашел точный коммит, где была представлена ​​проблема. Довольно здорово.


2

Не уверен, почему принятый ответ не работает в моей среде, наконец, я запускаю команду ниже, чтобы получить то, что мне нужно

git log --pretty=format:"%h - %an, %ar : %s"|grep "STRING"
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.