Код-ревью и защита веток

Урок про то, как устроить ревью кода через Pull Request и техническими средствами не дать влить в основную ветку непроверенный код.

Branch protection — правила на стороне платформы (GitHub/GitLab), которые запрещают вливать в защищённую ветку код, пока не выполнены условия: пройдено ревью и зелёные проверки.

Зачем процесс, а не «просто посмотреть код»

Код-ревью «по доброй воле» не работает: под дедлайн его пропускают, в main пушат напрямую, баги уходят в прод. Поэтому ревью делают обязательным этапом, который нельзя обойти технически. Pull Request (на GitHub) или Merge Request (на GitLab) — это и есть единица ревью: ветка с изменениями, обсуждением и набором автоматических проверок, которую невозможно слить, не выполнив правила.

Pull Request как процесс

Жизненный цикл PR обычно такой: автор пушит ветку и открывает PR → запускается CI → ревьюеры читают diff, оставляют комментарии и запрашивают правки → автор отвечает коммитами → когда есть аппрув и проверки зелёные, PR вливается. Хороший PR маленький и сфокусированный: ревьюеру проще внимательно прочитать 200 строк, чем 2000. Не менее важно качественное описание: что изменилось, зачем, как проверить, на что обратить внимание. Описание экономит ревьюеру десятки минут на реконструкцию контекста и часто становится частью истории — особенно при squash-слиянии, когда текст PR уходит в коммит и changelog.

Ревью — это ещё и канал распространения знаний. Когда второй человек читает чужой код, по команде расходится понимание того, как устроена система; снижается «фактор автобуса», находятся не только баги, но и более простые решения. Поэтому ревью оставляют даже там, где автор технически мог бы влить сам: ценность не только в ловле ошибок, но и в общей ответственности за код. Комментарии при этом полезно разделять на блокирующие («так нельзя, поправь») и необязательные («nit: можно красивее») — это ускоряет договорённость и не превращает ревью в бесконечный спор о вкусах.

git checkout -b feat/search-filters
# ... работаем ...
git push -u origin feat/search-filters

# через GitHub CLI можно открыть PR прямо из терминала
gh pr create --fill --base main
gh pr view --web

Required reviews: обязательные аппрувы

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

  • минимум аппрувов (часто 1–2);
  • dismiss stale approvals — сбрасывать одобрение, если после него запушены новые коммиты (иначе аппрувнут одно, а вольют другое);
  • require review from Code Owners — обязательно одобрение владельца затронутого кода.

CODEOWNERS: кто отвечает за код

Файл CODEOWNERS (в корне, в .github/ или docs/) сопоставляет пути с ответственными людьми/командами. Если PR трогает эти файлы, платформа автоматически назначит владельцев ревьюерами, а при включённом правиле — потребует их аппрув.

# синтаксис: путь  владельцы
*                       @org/core-team
/frontend/              @org/frontend-team
/backend/billing/       @alice @bob
*.sql                   @org/dba

Так нельзя случайно изменить биллинг или схему БД без участия тех, кто за них отвечает. Правила читаются сверху вниз, и побеждает последнее совпавшее: общая строка * задаёт владельцев по умолчанию, а более конкретные пути ниже переопределяют их для своих участков. Это удобно в больших репозиториях, где у каждого модуля своя команда: ревью автоматически попадает к тем, кто реально разбирается в затронутой области, а не к случайному дежурному. Важно держать файл в актуальном состоянии — устаревший CODEOWNERS назначает ревьюерами людей, давно ушедших из команды, и блокирует PR.

Status checks: зелёный CI как пропуск

Status checks — это внешние проверки (тесты, линтер, сборка, сканер безопасности), которые сообщают платформе свой статус. В branch protection можно сделать конкретные проверки обязательными: пока они не «зелёные», кнопка слияния заблокирована. Это и есть техническое воплощение идеи «main всегда зелёный» из предыдущих уроков: ни один PR с падающими тестами просто не доедет до основной ветки, какой бы срочной ни была задача. Часто включают и require branches to be up to date — PR должен содержать свежий main, чтобы проверки шли на актуальном коде. Без этого возможна коварная ситуация: ваш PR зелёный, соседний зелёный, но вместе после слияния они конфликтуют по смыслу, и main ломается, хотя каждый по отдельности проходил.

# .github/workflows/ci.yml — этот workflow становится status check
name: ci
on: [pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm test

Имя job (test) появится в списке проверок PR; его и отмечают обязательным в настройках ветки.

Draft PR: ранняя обратная связь без «зелёного света»

Иногда нужно показать направление до готовности. Draft (черновой) PR помечается как «ещё не для слияния»: его нельзя замёржить и обычно он не дёргает ревьюеров уведомлениями, но CI и обсуждение уже доступны. Когда работа готова — переводят в обычный статус («Ready for review»).

gh pr create --draft --fill
# когда готово:
gh pr ready

Как это работает под капотом

Защита ветки — это серверная политика платформы, а не функция самого Git. Технически она навешивается на операцию обновления ссылки (ref) refs/heads/main: попытка запушить напрямую или слить PR, не выполнив условия, отклоняется ещё до изменения указателя ветки. Поэтому правила нельзя обойти с локальной машины — решение принимает сервер. Status checks работают через статусы коммита (commit status / check run), которые CI выставляет по API; платформа просто читает их и решает, разблокировать ли слияние. CODEOWNERS платформа парсит как набор glob-правил и сопоставляет с файлами в diff.

Частые ошибки

  • Защита только UI, но push не запрещён. Если разрешён прямой git push в main, весь процесс PR обходится одной командой. Запрет прямого пуша обязателен.
  • Не сбрасывать устаревшие аппрувы. Без dismiss stale approvals можно получить аппрув, а потом дослать любой код — ревью становится фикцией.
  • Включить администраторам обход. Если main «защищён, но не для админов», правило регулярно нарушается «по-быстрому». Включайте include administrators.
  • Обязательные проверки без require up-to-date. PR могут протестировать на устаревшей базе, и поломка от свежего main просочится.
  • Гигантские PR. 3000 строк никто не ревьюит внимательно — аппрув ставят «не глядя». Дробите изменения.
  • Self-approve вместо ревью. Одобрять собственный PR — значит превращать защиту в формальность; требуйте аппрув другого человека.

Итоги

  • Pull/Merge Request — это единица ревью: diff + обсуждение + автоматические проверки.
  • Branch protection делает ревью неотменяемым на стороне сервера, а не «по договорённости».
  • Required reviews + dismiss stale approvals не дают влить неодобренный или подменённый код.
  • CODEOWNERS назначает ответственных за пути и может требовать их аппрув.
  • Status checks превращают зелёный CI в обязательный пропуск к слиянию.
  • Draft PR даёт раннюю обратную связь без риска преждевременного мёржа.
Проверьте себя
1. Что технически делает branch protection с настройкой «require pull request reviews»?
AЛокально блокирует git commit без аппрува
BНа стороне сервера отклоняет слияние/прямой push в защищённую ветку, пока не выполнены условия
CШифрует ветку до получения аппрува
DУдаляет ветку, если её не одобрили за сутки
2. Зачем нужен файл CODEOWNERS?
AХранить список всех контрибьюторов проекта
BСопоставлять пути файлов с ответственными, чтобы автоматически назначать и требовать их ревью
CЗадавать права доступа к репозиторию по SSH
DОписывать формат сообщений коммитов
3. Чем draft (черновой) Pull Request отличается от обычного?
AВ нём отключён весь CI
BЕго нельзя замёржить, он помечен как не готовый к слиянию, но обсуждение и проверки доступны
CОн виден только автору
DОн автоматически вливается после прохождения тестов
4. Зачем включать настройку «dismiss stale approvals» (сбрасывать устаревшие одобрения)?
AЧтобы ускорить прохождение CI
BЧтобы аппрув автоматически снимался при новых коммитах и нельзя было одобрить одно, а влить другое
CЧтобы запретить создавать новые ветки
DЧтобы автоматически закрывать неактивные PR