Git

Модуль 7: Командная работа и продвинутые практики

Git — это не только инструмент для одного разработчика. Его главная сила проявляется в командной работе. В этом модуле мы разберём полный цикл: от создания Pull Request до релиза, включая code review, модели ветвления, stash, cherry-pick и теги.

Командная работа — это набор договорённостей. Git предоставляет механизмы, но культура и политики команды определяют, как именно их применять.

7.1 Pull Request / Merge Request

Pull Request (на GitHub) или Merge Request (на GitLab) — это запрос на слияние вашей ветки в основную. Это не просто «кнопка merge» — это полноценный процесс обсуждения и проверки кода.

Жизненный цикл PR

  1. Создание веткиgit switch -c feature/user-profile
  2. Разработка — коммиты, тесты, документация
  3. Push веткиgit push -u origin feature/user-profile
  4. Создание PR — через веб-интерфейс GitHub/GitLab
  5. Code Review — коллеги проверяют и комментируют
  6. Исправления — новые коммиты по замечаниям
  7. Approve — ревьюеры одобряют
  8. Merge — слияние в main
  9. Удаление ветки — ветка больше не нужна

Как написать хороший PR

Шаблон описания PR

## Что сделано
Краткое описание изменений (1-3 предложения)

## Зачем
Ссылка на задачу/тикет, мотивация изменений

## Как протестировать
1. Шаг 1
2. Шаг 2
3. Ожидаемый результат

## Скриншоты (если UI)
...

## Чеклист
- [ ] Тесты написаны и проходят
- [ ] Документация обновлена
- [ ] Нет console.log / print для отладки

Создание PR через CLI

# GitHub CLI (gh)
gh pr create --title "feat: профиль пользователя" \
  --body "Добавляет страницу профиля с аватаром и настройками" \
  --base main

# Посмотреть свои PR
gh pr list --author @me

# Посмотреть статус проверок
gh pr checks

# Слить PR
gh pr merge --squash

Совет: Маленькие PR ревьюятся быстрее. Старайтесь, чтобы один PR содержал одно логическое изменение. PR на 50 строк получит ревью за час, PR на 500 строк — за неделю (если вообще).

7.2 Code Review: как давать и принимать ревью

Code review — это не «проверка на ошибки». Это процесс обмена знаниями, улучшения качества кода и выравнивания стандартов в команде.

Как проводить ревью (для ревьюера)

Чеклист ревьюера

  • Корректность: код делает то, что заявлено? Есть ли edge-cases?
  • Читаемость: понятен ли код без объяснений? Хорошие имена переменных?
  • Архитектура: вписывается ли изменение в существующую структуру проекта?
  • Тесты: покрыты ли основные сценарии? Тесты проходят?
  • Безопасность: нет ли SQL-инъекций, утечек секретов, XSS?
  • Производительность: нет ли N+1 запросов, утечек памяти?

Как писать комментарии

  • Будьте конкретны: не «плохо», а «эта функция делает слишком много — предлагаю разбить на validateInput() и processData()»
  • Объясняйте почему: не «переименуй», а «имя data не говорит о содержимом, предлагаю userProfiles»
  • Разделяйте критичное и некритичное: используйте префиксы nit: (мелочь), blocking: (нужно исправить)
  • Предлагайте решения: покажите код, а не только проблему

Как принимать ревью (для автора)

  • Не воспринимайте замечания как критику лично — ревьюят код, не вас
  • Отвечайте на каждый комментарий: «Исправил», «Не согласен, потому что...», «Давай обсудим»
  • Правки делайте отдельными коммитами (чтобы ревьюер видел, что изменилось)
  • После финального approve — squash/merge
# Посмотреть изменения в PR локально
gh pr checkout 42

# Или вручную:
git fetch origin pull/42/head:pr-42
git switch pr-42

7.3 Теги и релизы

Теги — это именованные указатели на конкретные коммиты. Чаще всего используются для маркировки релизных версий.

Два типа тегов

# Лёгкий тег (lightweight) — просто указатель
git tag v1.0.0

# Аннотированный тег (рекомендуется) — хранит автора, дату, сообщение
git tag -a v1.0.0 -m "Release 1.0.0: начальный публичный релиз"

# Посмотреть информацию о теге
git show v1.0.0

Работа с тегами

# Список тегов
git tag -l
git tag -l "v1.*"     # только версии 1.x

# Создать тег на старом коммите
git tag -a v0.9.0 abc1234 -m "Ретроспективный тег"

# Отправить тег на сервер
git push origin v1.0.0

# Отправить все теги
git push origin --tags

# Удалить тег локально и на сервере
git tag -d v1.0.0
git push origin --delete v1.0.0

Рекомендация: всегда используйте аннотированные теги для релизов. Они хранят метаданные и могут быть подписаны GPG-ключом для верификации.

7.4 Временное сохранение: git stash

Stash — это «карман» для незавершённых изменений. Типичная ситуация: вы работаете над фичей, и тут приходит срочный баг-репорт. Нужно переключиться на другую ветку, но текущие изменения ещё не готовы для коммита.

Основные команды

# Сохранить текущие изменения в stash
git stash push -m "WIP: форма логина"

# Или короткая форма
git stash

# Сохранить включая untracked файлы
git stash push -u -m "WIP: с новыми файлами"

# Посмотреть список stash'ей
git stash list
# stash@{0}: On feature/auth: WIP: форма логина
# stash@{1}: On main: WIP: рефакторинг

# Применить последний stash и удалить его
git stash pop

# Применить конкретный stash без удаления
git stash apply stash@{1}

# Посмотреть, что в stash'е (diff)
git stash show -p stash@{0}

# Удалить конкретный stash
git stash drop stash@{0}

# Удалить все stash'и
git stash clear

Практический сценарий

# Вы работаете над фичей...
# Приходит срочный баг:

# 1. Сохраняем незавершённую работу
git stash push -m "WIP: форма регистрации"

# 2. Переключаемся на main и создаём ветку для хотфикса
git switch main
git switch -c hotfix/critical-bug

# 3. Чиним баг, коммитим, мёржим
git commit -am "fix: критический баг в оплате"
git switch main
git merge hotfix/critical-bug

# 4. Возвращаемся к фиче и достаём stash
git switch feature/registration
git stash pop

# Продолжаем работу как ни в чём не бывало!

Совет: Всегда давайте stash'у осмысленное сообщение через -m. Через неделю stash@{3}: WIP ни о чём не скажет, а stash@{3}: WIP: форма логина с валидацией — понятно сразу.

7.5 Cherry-pick: перенос отдельных коммитов

cherry-pick берёт один конкретный коммит из другой ветки и применяет его к текущей. Это не merge целой ветки — это «вишенка с торта».

Когда использовать

  • Хотфикс нужен и в main, и в release-ветке
  • Из большой ветки нужен только один конкретный коммит
  • Нужно вернуть коммит, который был потерян при неудачном rebase
# Перенести один коммит
git cherry-pick abc1234

# Перенести несколько коммитов подряд
git cherry-pick abc1234 def5678 ghi9012

# Перенести диапазон коммитов (от A до B включительно)
git cherry-pick A^..B

# Cherry-pick без автоматического коммита (только staged)
git cherry-pick --no-commit abc1234

# Если возник конфликт:
git cherry-pick --continue    # после разрешения
git cherry-pick --abort       # отменить

Осторожно: cherry-pick создаёт новый коммит с новым хешем (но тем же содержимым). Git не знает, что это «тот же» коммит. Если потом мержить ветки — возможны дублирования и конфликты.

7.6 Модели ветвления

Модель ветвления — это договорённость команды о том, какие ветки существуют, как они называются и когда сливаются.

GitHub Flow (простая модель)

Принцип: ветка → PR → merge

  • main — всегда рабочая, деплоится автоматически
  • Для каждой задачи создаётся ветка от main
  • Готово → PR → code review → merge в main
  • Нет отдельных веток develop, release, hotfix

Подходит для: небольших команд, SaaS-продуктов, непрерывного деплоя.

GitFlow (классическая модель)

Долгоживущие ветки

  • main — только релизы, каждый коммит = тег версии
  • develop — текущая разработка, сюда мёржатся фичи
  • feature/* — ответвления от develop для каждой фичи
  • release/* — подготовка релиза (фиксы, версии, документация)
  • hotfix/* — срочные исправления от main

Подходит для: больших команд, продуктов с версионными релизами, мобильных приложений.

Trunk-based Development

Минимум ветвления

  • Все работают в main (trunk)
  • Ветки максимально короткоживущие (1-2 дня)
  • Непрерывная интеграция — мёржим несколько раз в день
  • Feature flags вместо долгих веток

Подходит для: команд с сильной CI/CD культурой, Google/Meta-масштаб.

7.7 Защищённые ветки и политики

Защита веток предотвращает случайные (и намеренные) нарушения процесса. Настраивается в GitHub/GitLab/Bitbucket.

Типичные политики

  • Запрет push напрямую: все изменения только через PR
  • Обязательный review: минимум 1-2 approve перед merge
  • Обязательные CI-проверки: тесты, линтинг, сборка должны пройти
  • Запрет force-push: нельзя переписывать историю защищённой ветки
  • Подпись коммитов: обязательная GPG/SSH подпись
  • Linear history: только rebase-merge или squash, без merge-коммитов

Минимальный набор для начала: защитите main от прямого push + обязательный 1 approve + CI-проверки. Этого достаточно для большинства команд.

7.8 Подпись коммитов (GPG/SSH)

Подпись коммитов подтверждает, что коммит действительно создан тем, за кого себя выдаёт автор. На GitHub подписанные коммиты получают значок «Verified».

# Настройка подписи через SSH (проще, чем GPG)
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true

# Теперь все коммиты будут подписаны автоматически
git commit -m "feat: подписанный коммит"

# Проверить подпись
git log --show-signature

7.9 DCO и шаблоны PR

Developer Certificate of Origin — юридическое подтверждение авторства. Используется в open-source проектах (Linux kernel, CNCF-проекты).

# Добавить DCO sign-off к коммиту
git commit -s -m "feat: новая функция"
# Результат: сообщение + "Signed-off-by: Имя <email>"

# Добавить sign-off к последнему коммиту
git commit --amend -s --no-edit

7.10 Семантическое версионирование и релизы

Semantic Versioning (SemVer) — стандарт нумерации версий: MAJOR.MINOR.PATCH.

Правила SemVer

  • MAJOR (1.x.x → 2.0.0): ломающие изменения API, несовместимость
  • MINOR (1.1.x → 1.2.0): новая функциональность, обратная совместимость
  • PATCH (1.1.1 → 1.1.2): баг-фиксы, без новой функциональности
# Полный цикл релиза:

# 1. Создать release-ветку
git switch -c release/1.2.0

# 2. Обновить версию в файлах (package.json, setup.py и т.д.)
# 3. Обновить CHANGELOG.md

# 4. Коммит и тег
git commit -am "release: v1.2.0"
git tag -a v1.2.0 -m "Release 1.2.0: добавлен профиль пользователя"

# 5. Слить в main и push
git switch main
git merge --no-ff release/1.2.0
git push origin main --tags

# 6. Создать GitHub Release (автоматически по тегу или вручную)
gh release create v1.2.0 --title "v1.2.0" --notes "Добавлен профиль пользователя"

Практическое задание

Задание 1: Полный цикл PR

  1. Создайте репозиторий на GitHub (или локально с git init --bare)
  2. Клонируйте, создайте ветку feature/about-page
  3. Сделайте 3 коммита, запушьте ветку
  4. Создайте PR (через gh pr create или веб-интерфейс)
  5. Добавьте описание по шаблону из раздела 7.1

Задание 2: Stash workflow

  1. Начните редактировать файл в feature-ветке (не коммитьте)
  2. Сохраните в stash: git stash push -m "описание"
  3. Переключитесь на main, сделайте хотфикс, вернитесь
  4. Восстановите stash: git stash pop

Задание 3: Cherry-pick хотфикса

  1. В ветке feature сделайте коммит с исправлением бага
  2. Переключитесь на main
  3. Перенесите только этот коммит: git cherry-pick <hash>
  4. Проверьте, что исправление есть в обеих ветках

Настройки

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

Тема