Git

Модуль 2: Углубляемся в коммиты и историю

Учимся читать историю, смотреть диффы коммитов, исправлять последний коммит и добавлять изменения частями. Разберём структуру коммита и лучшие практики оформления сообщений.

О чём этот модуль

  • Структура коммита: дерево файлов, родитель, автор/коммиттер, сообщение
  • Чтение истории: oneline/graph/decorate, фильтры по файлам/авторам/датам
  • Правки: --amend и аккуратное использование
  • Точечные добавления: git add -p для «чистых» коммитов
  • .gitignore: исключаем лишнее из истории

Хорошие сообщения к коммитам

  • Короткая заголовочная строка (до ~72 символов), затем пустая строка и подробности
  • Используйте стиль Conventional Commits: feat:, fix:, docs:, refactor: и т.п.
  • Пишите почему, а не только что

Чтение истории — это не столько набор флагов к git log, сколько умение формулировать вопрос к истории: «кто и когда трогал этот файл?», «какие коммиты привели к регрессии?», «почему появилось это решение?». Освоив фильтры и форматы вывода, вы превращаете историю в полноценный инструмент анализа.

2.1 Анализ истории: git log

git log --oneline --graph --decorate --all
# Отбор по автору/дате/файлу
git log --author="Ivan" --since="2024-01-01" -- README.md
# Показать статистику
git log --stat
# Дифф внутри лога
git log -p -- foo.txt

Старайтесь подбирать формат под задачу. Краткий «граф» полезен для ориентирования, а детальный -p — для изучения контекста изменений. Помните о диапазонах и селекторах: они позволяют сфокусироваться на интересующем промежутке истории.

2.2 Просмотр конкретного коммита: git show

git show <commit-hash>
# Показать только сообщение
git show -s --format=%B <hash>

git show — это «лупа» для одного коммита: кто автор, какие файлы затронуты, какие строки изменены. Умение быстро читать такие диффы экономит часы на ревью и отладке.

2.3 Изменение последнего коммита: --amend

# Добавить забытые файлы в предыдущий коммит
git add src/missed.py
git commit --amend --no-edit

# Изменить сообщение последнего коммита
git commit --amend -m "fix: корректирует обработку ошибок"

--amend переписывает заголовок истории, создавая новый коммит вместо старого. Это безопасно локально, но опасно для уже опубликованных веток: чужие репозитории потеряют ссылочную целостность.

Важно: не амендьте коммиты, которые уже ушли на общий remote.

2.4 Интерактивное добавление: git add -p

Позволяет выбрать части файла (hunks) для включения в коммит, делая коммиты «цельными».

git add -p
# Клавиши: y (принять), n (пропустить), e (редактировать), s (разбить), q (выход)

Мыслите «единицами смысла»: отдельный фикс — отдельный коммит. Интерактивное добавление помогает отделить косметику от логики, а эксперимент — от результата.

2.5 Игнорирование файлов: .gitignore

# .gitignore
__pycache__/
*.log
.env
build/

Шаблоны в .gitignore работают на уровне путей и масок. Для локальных исключений используйте .git/info/exclude. Не добавляйте в историю артефакты сборки и секреты — это усложняет ревью и раздувает репозиторий.

2.6 Анатомия коммита

Коммит — это объект в базе Git, содержащий:

  • tree — ссылка на дерево (полный снимок всех файлов)
  • parent — ссылка на родительский коммит (или два при merge)
  • author — кто написал изменения (имя, email, время)
  • committer — кто записал коммит (может отличаться от автора)
  • message — сообщение к коммиту
# Посмотреть внутреннюю структуру коммита
git cat-file -p HEAD
# tree 4a2e3f...
# parent abc1234...
# author Иван <ivan@example.com> 1708000000 +0300
# committer Иван <ivan@example.com> 1708000000 +0300
#
# feat: добавить авторизацию

2.7 Автор и коммиттер

Author — кто написал изменения. Committer — кто записал их в репозиторий. Они могут различаться:

  • После rebase — автор сохраняется, коммиттер меняется на того, кто делал rebase
  • После cherry-pick — аналогично
  • При git am (применение патча) — автор из патча, коммиттер — вы
# Посмотреть автора и коммиттера
git log --format="%H%nAuthor: %an <%ae> %ai%nCommitter: %cn <%ce> %ci%n" -1

2.8 Сообщения коммитов и трейлеры

Хорошее сообщение коммита состоит из трёх частей:

# 1. Заголовок (до 72 символов, повелительное наклонение)
feat: добавить авторизацию по JWT

# 2. Тело (через пустую строку, подробности)
Реализована авторизация с использованием JWT-токенов.
Добавлены middleware для проверки токена и обновления
refresh-токена.

# 3. Трейлеры (метаданные для инструментов)
Refs: #142
Co-authored-by: Пётр <petr@example.com>
Signed-off-by: Иван <ivan@example.com>

2.9 Диапазоны и селекторы

# HEAD~N — N коммитов назад по первому родителю
git log HEAD~3   # 3 коммита назад

# HEAD^ — первый родитель (HEAD^2 — второй, для merge-коммитов)
git show HEAD^

# A..B — коммиты, которые есть в B, но нет в A
git log main..feature   # что нового в feature

# A...B — коммиты, уникальные для каждой ветки
git log main...feature

# По дате
git log --since="2025-01-01" --until="2025-02-01"

# По автору
git log --author="Иван"

# По слову в сообщении
git log --grep="авторизация"

2.10 Продвинутые diff и log

# Пословное сравнение (для текстов, markdown)
git diff --word-diff

# Игнорировать пробелы
git diff -w

# Показать переименования файлов
git diff --find-renames

# Статистика изменений
git diff --stat

# Кто последний менял каждую строку
git blame path/to/file

# blame с игнорированием пробелов
git blame -w path/to/file

2.11 Поиск: pickaxe и git bisect

# Pickaxe: найти коммиты, которые добавили/удалили строку
git log -S "password" --oneline   # где появилось слово "password"
git log -G "def validate_" --oneline  # регулярное выражение

# Pathspec: ограничить область поиска
git log -- src/auth/     # только изменения в каталоге auth

# git bisect: бинарный поиск коммита с багом
git bisect start
git bisect bad              # текущий коммит — баг
git bisect good abc1234     # этот коммит был без бага
# Git переключается на средний коммит — тестируйте
git bisect good  # или git bisect bad
# Повторяйте, пока Git не найдёт виновный коммит
git bisect reset            # вернуться к исходному состоянию

2.12 Кастомные форматы вывода

# Кастомный формат
git log --pretty=format:"%h %an %ar %s" -10
# abc1234 Иван 2 hours ago feat: добавить авторизацию

# Алиасы для частых команд (добавить в .gitconfig)
git config --global alias.lg "log --oneline --graph --decorate --all"
git config --global alias.st "status -sb"
git config --global alias.last "log -1 --format='%H %s'"

# Теперь можно использовать:
git lg
git st
git last

Настройки

Цветовая схема

Тема