Олег Марков
Поиск по сообщению git log --grep
Введение
Поиск по истории коммитов — один из самых частых сценариев работы с Git. Очень часто нужно ответить на вопросы:
- кто добавил эту логику;
- когда появился конкретный баг;
- в каком коммите упоминался определенный тикет или задача;
- где в истории фигурировала фраза fix race condition или FEATURE PAYMENTS.
Для этого в Git есть мощный инструмент — поиск по сообщению коммита с помощью опции --grep в команде git log.
В этой статье вы увидите, как работает git log --grep, как настраивать чувствительность к регистру, использовать регулярные выражения, комбинировать поиск по сообщению с другими фильтрами (--author, --since, --grep + -S и т.д.) и как не попасть в типичные ловушки.
Что делает git log --grep
Основная идея
Опция --grep говорит git log отфильтровать коммиты по содержимому сообщения (subject + body). То есть Git будет просматривать именно текст коммитов: строку заголовка и основное описание, а не измененные файлы и строки кода.
Простейший пример:
git log --grep="BUG-1234"
# Здесь Git покажет только те коммиты,
# в сообщении которых встречается строка "BUG-1234"
Смотрите, я покажу вам, как это воспринимает Git:
- берется каждое сообщение коммита;
- к нему применяется поиск по шаблону
--grep="..."; - если сообщение совпало с шаблоном — коммит отображается, иначе пропускается.
Важно понимать: по умолчанию --grep использует регулярные выражения (regexp), а не простой "поиск подстроки" в привычном смысле. Но если вы не используете спецсимволы регулярок (., *, ?, [], ^, $ и т.п.), это фактически будет выглядеть как поиск подстроки.
Базовое использование git log --grep
Поиск по точной подстроке (практически)
Давайте разберемся на простом примере, когда вам нужно найти все коммиты, где в тексте сообщения встречается слово refactor.
git log --grep="refactor"
Как видите, команда:
- выведет список коммитов с сообщениями, в которых есть
refactor(в любом месте сообщения); - не учитывает регистр, если включена настройка
grep.patternType=basicи не указаны параметры чувствительности. Чтобы точно контролировать регистр, лучше явно задавать флаги, о них поговорим дальше.
Сразу полезный флаг для удобного просмотра:
git log --grep="refactor" --oneline
# --oneline - выводит каждый коммит в одну строку
# удобно для быстрого просмотра результатов поиска
Еще один часто полезный флаг — -p, чтобы сразу увидеть изменения:
git log --grep="refactor" -p
# -p - показывает diff для каждого найденного коммита
Поиск по нескольким словам
Если вы хотите искать сразу несколько разных фраз, можно передать --grep несколько раз:
git log --grep="BUG-" --grep="HOTFIX"
# Здесь будут показаны коммиты, в сообщениях которых
# есть либо "BUG-", либо "HOTFIX"
По умолчанию несколько --grep связываются как логическое "ИЛИ" (OR). То есть коммит попадет в результат, если удовлетворяет хотя бы одному шаблону.
Позже вы увидите, как переключиться на логику "И" (AND).
Управление регистром: учитывать или игнорировать
Флаг -i (ignore case)
Поиск по умолчанию может зависеть от настроек Git, но чтобы не гадать, проще явно использовать флаг -i, который игнорирует регистр:
git log --grep="fix" -i --oneline
# Найдет "fix", "Fix", "FIX" и любые другие варианты
Теперь вы уверены, что не пропустите коммиты из-за разницы в регистре.
Обратный случай — чувствительный к регистру поиск
Если по какой-то причине у вас глобальные настройки заставляют Git игнорировать регистр, можно включить чувствительность к регистру через --regexp-ignore-case=false, но на практике проще настраивать это через конфиг git config или использовать шаблоны регулярок, различающих регистр. Для большинства сценариев достаточно знать и применять флаг -i.
Использование регулярных выражений в --grep
Теперь давайте посмотрим, как использовать силу регулярок, а не только простую подстроку.
Простейший пример с регулярными выражениями
Предположим, вы ведете задачи в таком формате: TASK-123, TASK-456, TASK-789. Вам нужно найти все коммиты, где в сообщении был упомянут любой идентификатор задачи.
git log --grep="TASK-[0-9]\+"
# TASK- + одна или больше цифр
# \+ - квантификатор "один или более" в basic regexp
По умолчанию Git использует "basic" регулярные выражения (BRE), в которых некоторые спецсимволы нужно экранировать с помощью обратного слэша.
Если вам привычнее "extended" регулярные выражения (ERE), можно переключить режим.
Переключение типа регулярок
Git поддерживает несколько типов регулярных выражений через опцию --regexp-type:
basic(по умолчанию во многих конфигурациях);extended;perl(PCRE);fixed(поиск буквальной строки).
Пример с расширенными регулярками:
git log --grep="TASK-[0-9]+" --regexp-type=extended
# Здесь "+" уже не нужно экранировать
Пример с perl-совместимыми регулярками:
git log --grep="TASK-(\d{3,5})" --regexp-type=perl
# (\d{3,5}) - 3–5 цифр подряд
Поиск по началу или концу строки
Иногда нужно найти коммиты, у которых заголовок сообщения начинается с определенного префикса. Например, все фиксы:
git log --grep="^fix" --oneline
# Найдет сообщения, где строка начинается с "fix"
Или наоборот — сообщения, заканчивающиеся на ! (например, для breaking changes):
git log --grep="!$" --oneline
# Найдет заголовки/строки, которые заканчиваются на "!"
Поиск по нескольким вариантам в одном шаблоне
Представьте, что вы хотите найти упоминания задач разных типов: BUG-123, TASK-456, FEATURE-789. Можно объединить варианты в один шаблон:
git log --grep="\(BUG\|TASK\|FEATURE\)-[0-9]\+"
# В basic regexp "или" записывается как \(A\|B\)
Если включить extended-режим, запись упростится:
git log --grep="(BUG|TASK|FEATURE)-[0-9]+" --regexp-type=extended
Теперь Git покажет все коммиты, где в сообщении была ссылка на любую из этих задач.
Комбинация нескольких --grep: логика AND/OR
Поведение по умолчанию — OR
Как уже упоминалось, если вы укажете несколько --grep без дополнительных опций, Git будет использовать логику "ИЛИ":
git log --grep="refactor" --grep="cleanup"
# Показать коммиты, где есть ИЛИ "refactor", ИЛИ "cleanup"
Здесь достаточно совпадения по любому одному шаблону.
Логика AND: флаг --all-match
Если вы хотите найти коммиты, в сообщении которых встречаются сразу все указанные фразы (логика "И"), используйте --all-match.
Давайте посмотрим на примере. Допустим, вам нужны коммиты, в сообщении которых присутствуют и BUG- и database:
git log --grep="BUG-" --grep="database" --all-match
# Будут показаны только те коммиты, в сообщении которых
# одновременно есть и "BUG-" и "database"
Важно: --all-match относится ко всем --grep в команде, но не распространяется, например, на --author или --committer. То есть логика "И" применяется только между шаблонами --grep.
Комбинация --grep с другими фильтрами git log
git log умеет фильтровать коммиты по множеству критериев: автор, дата, файлы, диапазоны коммитов, содержимое изменений и т.д. В реальной работе поиск по сообщению редко используется изолированно — вы почти всегда будете комбинировать --grep с чем-то еще.
Поиск по сообщению и автору
Допустим, вы хотите найти все коммиты, где упоминался тикет PAY-101, и при этом их делал конкретный разработчик:
git log --grep="PAY-101" --author="Иван" --oneline
# Найдет только те коммиты, где:
# - в сообщении есть "PAY-101"
# - автор коммита содержит подстроку "Иван"
Опция --author сама по себе тоже использует регулярные выражения. Можно написать, например:
git log --grep="PAY-101" --author="ivan\.petrov@company\.com"
Поиск по сообщению и диапазону времени
Очень частый сценарий — "найти все коммиты с упоминанием migration за последние 2 недели". Теперь давайте перейдем к примеру:
git log --grep="migration" --since="2 weeks ago" --oneline
# --since - фильтр по дате, всё что новее указанной точки
Можно, наоборот, ограничить историю по верхней границе:
git log --grep="migration" --until="2023-12-31" --oneline
Или использовать обе границы сразу:
git log --grep="migration" --since="2023-12-01" --until="2023-12-31"
Поиск по сообщению и файлам
Если нужно найти коммиты, в которых изменялся конкретный файл и в сообщении фигурировала определенная фраза, можно сочетать --grep с указанием путей.
Например, вас интересуют все коммиты, где обновлялся файл app/config.yml и упоминался redis:
git log --grep="redis" -- app/config.yml
# Обратите внимание:
# после двойного дефиса "--" идут пути к файлам/каталогам
Если путь идет без --, Git может попытаться воспринять его как часть параметров, поэтому принято ставить разделитель --, когда вы указываете файлы.
Отличия --grep от -S и -G (поиск по коду, а не по сообщению)
Иногда разработчики путают --grep с опциями -S и -G, которые ищут по содержимому изменений (diff), а не по тексту сообщения.
Давайте коротко разберем отличие.
--grep — ищет по сообщению
То, о чем идет речь в этой статье, — поиск по тексту сообщения коммита (того, что вы пишете при выполнении git commit).
git log --grep="API change"
# Ищет по заголовку и телу сообщения
-S — поиск по добавленным/удаленным строкам
Опция -S ищет коммиты, в которых была добавлена или удалена строка, содержащая конкретный текст. Она смотрит на diff, а не на сообщение.
git log -S"GetUserByID" -p
# Найдет коммиты, где упоминание "GetUserByID"
# появлялось или исчезало в коде/файлах
-G — поиск по регулярному выражению в изменениях
Опция -G похожа на -S, но принимает на вход регулярное выражение для поиска по измененным строкам.
git log -G"TODO.*remove" -p
# Найдет коммиты, где среди измененных строк
# были строки, соответствующие этому шаблону
Комбинация --grep с -S / -G
Вы можете одновременно фильтровать и по сообщению, и по содержимому изменений. Покажу вам, как это выглядит на практике:
git log --grep="BUG-123" -S"GetUserByID" -p
# Покажет только те коммиты, где:
# - в сообщении есть "BUG-123"
# - и в изменениях фигурировала строка с "GetUserByID"
Такая комбинация полезна, если вы хотите точно найти связку "этот тикет" + "конкретная функция/строка в коде".
Управление форматом вывода при использовании --grep
Чтобы результаты поиска были удобочитаемыми, git log позволяет довольно гибко настраивать формат вывода.
Короткий формат для просмотра списка
Чаще всего после фильтрации по --grep достаточно быстро посмотреть список найденных коммитов. Для этого удобно использовать:
git log --grep="refactor" --oneline --decorate
# --oneline - короткий формат (hash + subject)
# --decorate - показывает ссылки (ветки, теги) на коммит
Полный формат с датой и автором
Если вам важна дата и автор, добавьте флаг --pretty:
git log --grep="PAY-101" --pretty="%h %ad | %an | %s" --date=short
# %h - короткий hash
# %ad - дата автора
# %an - имя автора
# %s - заголовок сообщения
# --date=short - формат даты YYYY-MM-DD
Обратите внимание, как этот формат помогает быстро фильтровать глазами историю по нужным признакам.
Отображение только тела сообщений
Если вам интересно именно тело сообщения (body), а не полный лог с diff, можно настроить вывод так:
git log --grep="changelog" --pretty="commit %H%n%n%s%n%n%b%n"
# %H - полный hash
# %s - заголовок
# %b - тело сообщения
# %n - перевод строки
Практические сценарии использования git log --grep
Теперь давайте перейдем к нескольким живым сценариям, с которыми вы точно столкнетесь на практике.
Сценарий 1: поиск коммитов по идентификатору задачи
Предположим, в вашей команде принято указывать ID задачи в заголовке коммита, например:
BUG-1234 Fix crash on startupTASK-5678 Implement caching layer
Вы хотите найти все коммиты по задаче BUG-1234:
git log --grep="BUG-1234" --oneline
Если задачи могут упоминаться и в теле (особенно при squash- или merge-коммитах), этого все равно достаточно, потому что --grep смотрит и на заголовок, и на тело.
Сценарий 2: поиск "подозрительных" коммитов
Часто нужно найти "подозрительные" коммиты — например, все hotfix'ы или временные изменения.
git log --grep="hotfix" --grep="temp" --grep="quick fix" --oneline
# Ищем коммиты, где есть хотя бы один из этих маркеров
Если ваша команда договорилась помечать временный код словами WIP или TMP, вы можете отследить все такие коммиты:
git log --grep="WIP" --grep="TMP" --oneline
Сценарий 3: поиск breaking changes по префиксу в сообщении
Допустим, вы используете соглашение, где breaking changes помечаются так:
BREAKING: remove legacy v1 APIBREAKING: change auth token format
Тогда поиск будет выглядеть так:
git log --grep="^BREAKING" --oneline
# ^BREAKING - заголовок начинается с BREAKING
Так вы можете быстро собрать все потенциально опасные изменения и, например, подготовить release notes.
Сценарий 4: поиск изменений конфигурации или миграций
Нередко нужно быстро найти все коммиты, которые затрагивали миграции БД или конфигурацию.
Если команда придерживается конвенции по сообщениям, например:
db: add users tabledb: change index for paymentsconfig: update S3 credentials
То поиск будет таким:
git log --grep="^db:" --grep="^config:" --oneline
Если таких соглашений нет, можно ориентироваться по контрольным словам:
git log --grep="migration" --grep="schema" --oneline
Сценарий 5: анализ истории по конкретной теме за определенный период
Представим, что вам нужно собрать список всех коммитов, связанных с платежами, за последний месяц, чтобы оценить масштаб изменений.
git log --grep="payment" --grep="PAY-" -i \
--since="1 month ago" \
--oneline
Здесь мы:
- ищем по словам
paymentиPAY-(идентификатор тикетов); - игнорируем регистр (
-i); - ограничиваем поиск последним месяцем.
Производительность и ограничения при использовании --grep
Почему поиск может быть медленным
git log --grep вынужден "прочитать" сообщение каждого коммита в диапазоне, который вы ему задали. На маленьких репозиториях это незаметно, но в больших монорепозиториях с десятками или сотнями тысяч коммитов поиск может занимать ощутимое время.
Несколько практических советов:
Старайтесь ограничивать диапазон поиска:
- по времени (
--since,--until); - по ветке (
git log main --grep=...,git log release/1.2 --grep=...); - по путям (указание подкаталогов, если вас интересует только часть проекта).
- по времени (
Избегайте чрезмерно сложных регулярок, которые тяжелы для обработки.
При необходимости ищите сначала по более общему признаку (например, по тикету), а затем уточняйте поиск.
Когда git log --grep не поможет
Важно помнить: --grep не ищет по содержимому файлов, он смотрит только в текст сообщений коммитов. Поэтому:
- если нужное слово есть в коде, но не в сообщении —
--grepэто не найдет (нужны-Sили-G); - если кто-то сделал коммит без осмысленного сообщения ("fix", "update", "change"), найти такой коммит по смыслу будет трудно.
Лучшие практики использования сообщений коммитов для эффективного grep
Чтобы git log --grep был реально полезен, коммит-месседжи должны быть осмысленными и структурированными. Смотрите, от чего напрямую зависит удобство поиска:
- Наличие идентификаторов задач (например,
PROJ-123). - Наличие понятного глагола действия (
add,fix,refactor,remove). - Единые префиксы для областей системы (
db:,auth:,api:и т.п.).
Примеры хорошо структурированных сообщений:
PAY-101 fix double charge for recurring paymentsDB add index for user_id on payments tableAUTH refactor token validation logic
Такие сообщения очень удобно искать:
git log --grep="PAY-101" --oneline
git log --grep="^DB " --oneline
git log --grep="^AUTH refactor" --oneline
Если в команде сейчас нет соглашения по коммитам, имеет смысл договориться о формате и объяснить, как это помогает потом находить нужные изменения.
Заключение
Опция git log --grep — это удобный способ быстро находить нужные коммиты по тексту их сообщений. Вы можете:
- искать по простым подстрокам и по регулярным выражениям;
- настраивать чувствительность к регистру;
- объединять несколько
--grepчерез логику OR и AND (с--all-match); - комбинировать поиск по сообщению с фильтрами по автору, дате, диапазонам и файлам;
- сочетать
--grepс-Sи-G, когда нужно одновременно смотреть и на текст коммитов, и на измененный код.
Эффективность git log --grep во многом зависит от качества сообщений коммитов. Чем более структурированно команда пишет сообщения, тем проще потом анализировать историю и находить нужные изменения. Если вы будете системно использовать идентификаторы задач, осмысленные префиксы и ключевые слова, --grep превратится в мощный навигационный инструмент по истории репозитория.
Частозадаваемые технические вопросы по теме и ответы
Как искать по нескольким шаблонам так, чтобы хотя бы один из них сработал, и одновременно ограничить поиск веткой
git log main --grep="BUG-" --grep="HOTFIX" --oneline
# Поиск только в ветке main
# Будут показаны коммиты, где есть либо "BUG-", либо "HOTFIX"
Как исключить из результата коммиты с определенными словами в сообщении
Git не имеет прямого negation для --grep, но можно использовать grep Unix на выводе:
git log --oneline --grep="BUG-" | grep -v "WIP"
# Сначала находим все BUG-коммиты
# Потом отбрасываем строки, содержащие "WIP"
Как искать только по заголовку сообщения, игнорируя тело
Прямой опции "искать только по subject" нет, но можно использовать формат вывода и внешний grep:
git log --pretty="%H %s" | grep "BREAKING"
# Ищем только в заголовках (%s)
# Потом по hash можно сделать git show <hash>
Как вывести только hash найденных коммитов для дальнейшей обработки в скриптах
git log --grep="PAY-101" --pretty="%H"
# Каждый hash на отдельной строке
# Удобно использовать в циклах shell или других скриптах
Как искать по сообщению только в определенной поддиректории проекта
git log --grep="migration" -- db/migrations
# --grep применится к сообщениям,
# но в выборку попадут только коммиты, затрагивавшие db/migrations
Постройте личный план изучения Git до уровня Middle — бесплатно!
Git — часть карты развития Frontend
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Бесплатные лекции
Все гайды по Git
Лучшие курсы по теме

Основы Git
Антон Ларичев
TypeScript с нуля
Антон Ларичев