Инструкция

git log, diff, show и blame: как читать историю проекта в Git

Обновлено: · Skillaria.Top

git log показывает список коммитов и умеет фильтровать их по автору, дате, файлу и тексту; git diff сравнивает рабочую папку, индекс и любые коммиты; git show выводит один коммит целиком; git blame показывает, какой коммит последним менял каждую строку файла.

Четыре команды закрывают почти все вопросы к истории проекта. git log отвечает «что происходило», git diff — «что именно изменилось», git show — «что внутри конкретного коммита», git blame — «кто и когда написал эту строку». Ниже — рабочие приёмы для каждой, с флагами, которые реально используют в ежедневной разработке.

git log: список коммитов

Без аргументов git log выводит коммиты текущей ветки от новых к старым: полный хеш SHA-1, автор, дата и сообщение. Листается в пейджере (обычно less): пробел — следующая страница, /текст — поиск, q — выход.

commit 7be41d0c9a2e4f1b8d6c3e5a7f9b0c2d4e6f8a1b
Author: Anna Petrova <anna@example.com>
Date:   Mon Oct 5 14:22:10 2026 +0300

    feat: кэширование ответов API

Хеш не нужно копировать целиком: Git понимает любой уникальный префикс от 4 символов, на практике хватает 7.

Компактный вывод: --oneline

git log --oneline -10
# 7be41d0 (HEAD -> main, origin/main) feat: кэширование ответов API
# 1c02e8f fix: таймаут запросов
# 9a4b3c2 refactor: вынес клиент в модуль

Флаг -10 (или -n 10) ограничивает число коммитов. В скобках — указатели: где находятся HEAD, локальные и удалённые ветки, теги.

Граф веток: git log --graph

Запрос «git graph» обычно означает именно это: визуализацию ветвлений и слияний прямо в терминале.

git log --oneline --graph --all
# * 3e1f0aa (feature/auth) feat: вход по токену
# | * 7be41d0 (HEAD -> main) feat: кэширование ответов API
# |/
# * 1c02e8f fix: таймаут запросов
# *   5d2c7b1 Merge branch 'feature/search'
# |\
# | * 8f3a9e0 feat: поиск
# |/
# * 9a4b3c2 refactor: вынес клиент в модуль

--all показывает все ветки, а не только текущую. Удобно завести алиас: git config --global alias.lg "log --oneline --graph --all --decorate", после чего хватит git lg.

Свой формат: --pretty=format

git log --pretty=format:"%h %ad %an %s" --date=short
# 7be41d0 2026-10-05 Anna Petrova feat: кэширование ответов API

Основные плейсхолдеры: %h — короткий хеш, %H — полный, %an — автор, %ae — его e-mail, %ad — дата автора, %ar — относительная дата («2 days ago»), %s — заголовок сообщения.

Как отфильтровать историю в git log

По автору и дате

git log --author="Anna"
git log --since="2 weeks ago" --until="2026-10-01"
git log --since=yesterday --oneline

--author принимает регулярное выражение и ищет по имени и e-mail. Даты Git понимает и в свободной форме, и в ISO.

По тексту сообщения

git log --grep="fix" -i --oneline

-i делает поиск нечувствительным к регистру. Если ваша команда пишет номера задач в сообщениях, так быстро находятся все коммиты по задаче.

По файлу или папке

git log --oneline -- src/api/client.py
git log --follow -p -- src/api/client.py

Двойное тире отделяет пути от веток. --follow продолжает историю файла через переименования (работает для одного файла), -p показывает патч каждого коммита.

По изменённому коду: поиск «кирки»

git log -S "retry_count" --oneline     # коммиты, где менялось число вхождений строки
git log -G "timeout\s*=" --oneline    # коммиты, где в diff есть строки по regex

-S находит коммит, где функцию или переменную добавили либо удалили, — незаменимо, когда нужно понять, куда пропал кусок кода.

Диапазоны коммитов

git log main..feature      # что есть в feature, но нет в main
git log origin/main..HEAD  # мои локальные коммиты, ещё не отправленные
git log --no-merges        # без merge-коммитов
git log --stat             # какие файлы и сколько строк изменено

git diff: что именно изменилось

Главное, что нужно понять про git diff, — какие два состояния он сравнивает. Путаница здесь — причина вопроса «почему diff пустой, я же всё поменял».

КомандаЧто сравнивает
git diffрабочая папка против индекса (неподготовленные изменения)
git diff --staged (--cached)индекс против последнего коммита (что войдёт в коммит)
git diff HEADрабочая папка против последнего коммита (всё вместе)
git diff A Bдва коммита, ветки или тега
git diff A...Bизменения в B с момента ответвления от A

Если вы сделали git add, обычный git diff станет пустым — изменения уже в индексе, смотрите --staged. Новые, ни разу не добавленные файлы diff не показывает вообще.

Как читать вывод diff

diff --git a/config.py b/config.py
index 3b18e51..a1c4f02 100644
--- a/config.py
+++ b/config.py
@@ -10,7 +10,7 @@ DEFAULTS = {
     "host": "localhost",
-    "timeout": 5,
+    "timeout": 30,
     "retries": 3,

Строки с - удалены, с + добавлены, остальные — контекст. Заголовок @@ -10,7 +10,7 @@ означает: фрагмент начинается со строки 10 и занимает 7 строк в старой и новой версиях.

Полезные флаги git diff

git diff --stat main feature      # сводка по файлам
git diff --name-only HEAD~3       # только имена изменённых файлов
git diff --word-diff               # изменения по словам, удобно для текстов
git diff -w                        # игнорировать изменения пробелов
git diff main feature -- src/      # ограничить папкой

Перед каждым коммитом полезно смотреть git diff --staged: это последний шанс заметить отладочный print или случайно добавленный файл.

git show: один коммит целиком

git show выводит метаданные коммита и его diff относительно родителя. Без аргументов — последний коммит.

git show 7be41d0
git show HEAD~2 --stat           # без патча, только сводка
git show v1.2.0                  # тег: аннотация и коммит
git show main:src/config.py      # файл в том виде, как он был в коммите

Последняя форма <ревизия>:<путь> особенно полезна: можно посмотреть старую версию файла, не переключаясь на неё. Перенаправьте вывод в файл, и вы восстановите удалённое содержимое без checkout.

git blame: кто изменил эту строку

git blame файл для каждой строки показывает последний коммит, который её менял, автора и дату. Название звучит обвинительно, но на деле это инструмент поиска контекста: найти коммит, прочитать сообщение и понять, зачем так сделано.

git blame -L 40,60 src/api/client.py
# 1c02e8f3 (Anna Petrova 2026-09-28 11:04:51 +0300 41)     timeout = settings.timeout
# 9a4b3c2e (Ivan Smirnov 2026-09-14 18:30:02 +0300 42)     session = build_session()
  • -L 40,60 — только диапазон строк; можно и -L :имя_функции.
  • -w — игнорировать изменения пробелов, чтобы не попадать на коммиты форматирования.
  • -C — отслеживать строки, перенесённые из других файлов.
  • --ignore-rev <хеш> или файл .git-blame-ignore-revs — пропускать массовые коммиты вроде автоформатирования.

Типичный сценарий расследования: git blame находит коммит, git show показывает его целиком, git log по файлу даёт соседние изменения.

Ссылаться на коммиты можно не только хешами. HEAD~1 — родитель текущего коммита, HEAD~3 — прадед. HEAD^2 — второй родитель merge-коммита. Работают и имена веток, тегов, удалённых веток: origin/main~2. Посмотреть проект целиком на старом коммите можно через git switch --detach <хеш>, вернуться — git switch -.

Хорошая и плохая история

Все эти команды полезны ровно настолько, насколько осмысленна история. Сообщения вида «fix», «wip», «ещё правки» делают git log --grep и git blame бесполезными. Хороший коммит — одно логическое изменение и заголовок, который объясняет, что и зачем: fix: увеличен таймаут API до 30 с из-за медленного шлюза. Через полгода именно такой коммит найдёт blame и сэкономит вам час.

Практика: расследуем баг по истории

Допустим, после очередного релиза запросы к API стали падать по таймауту. Вот как связка команд приводит к причине за пару минут.

  1. Смотрим, что вошло в релиз: git log v1.4.0..v1.5.0 --oneline. Список короткий, но по заголовкам виновник неочевиден.
  2. Сужаем по файлу: git log v1.4.0..v1.5.0 --oneline -- src/api/. Остаются два коммита.
  3. Ищем по коду: git log -S "timeout" --oneline -- src/api/ находит коммит, где значение таймаута поменялось.
  4. Смотрим его целиком: git show 1c02e8f. В diff видно, что таймаут уменьшили с 30 до 5 секунд, а в сообщении объяснение — «ускоряем отклик UI».
  5. Проверяем, кто ещё трогал эту строку: git blame -L :build_session src/api/client.py.

Дальше решение уже инженерное: вернуть значение, вынести таймаут в настройки или откатить коммит через git revert. Если же коммитов сотни и найти виновника глазами нельзя, на помощь приходит git bisect — бинарный поиск по истории, который за несколько шагов указывает на коммит, сломавший поведение.

Настройки, которые упрощают жизнь

git config --global log.date iso            # формат дат в log
git config --global diff.colorMoved zebra   # подсветка перемещённых строк в diff
git config --global core.pager "less -FRX"  # не открывать пейджер для короткого вывода

Если вывод нужно обработать скриптом, отключите цвета и пейджер: git --no-pager log --format="%H %s" --no-color. Для машинной обработки используйте полный хеш %H: короткие префиксы со временем могут стать неоднозначными в большом репозитории.

Итог

git log с фильтрами --oneline, --graph, --author, -S и путями отвечает на вопрос «что происходило». git diff сравнивает рабочую папку, индекс и коммиты — главное помнить, что он сравнивает по умолчанию. git show раскрывает один коммит или старую версию файла, а git blame ведёт от строки кода к решению, которое её породило. Чтение истории и навигация по коммитам разобраны на практике в курсе по Git.

Частые вопросы

Как выйти из git log?

Нажмите q — вывод открыт в пейджере less; чтобы печатать без пейджера, используйте git --no-pager log или флаг -n с небольшим числом.

Как посмотреть историю удалённого файла?

Выполните git log --oneline -- путь/к/файлу (с двойным тире), а содержимое до удаления — git show &lt;хеш&gt;^:путь/к/файлу.

Как сравнить локальную ветку с удалённой?

Сначала git fetch, затем git diff origin/main или git log origin/main..HEAD, чтобы увидеть ваши неотправленные коммиты.

Есть ли графический просмотр истории?

Да, в комплекте с Git идёт gitk, а также граф истории встроен в VS Code, JetBrains IDE и веб-интерфейсы GitHub и GitLab.

Почему git diff ничего не показывает?

Скорее всего, изменения уже добавлены в индекс через git add — смотрите git diff --staged; новые неотслеживаемые файлы git diff не показывает вовсе.

Разберите тему на видео

Эта тема подробно разобрана с практикой в курсе «Git с нуля до уверенного разработчика».

Перейти к курсу