Автоматические проверки кода с помощью CODEOWNERS
Настройте GitHub CODEOWNERS, избегайте скрытых сбоев и включите code review через правильные шаблоны, права и защиту веток.
Файл CODEOWNERS — это текстовый файл в репозитории, который сопоставляет шаблоны путей с владельцами — пользователями или командами GitHub — и автоматически запрашивает проверку у этих владельцев каждый раз, когда pull request затрагивает соответствующий путь. Он выполняет две задачи одновременно: направляет проверки нужным людям без ручного упоминания и документирует, кто за что отвечает. Подводный камень в том, что CODEOWNERS не сообщает об ошибках. Неправильный порядок шаблонов, команда без участников или владелец без прав на запись не вызывают никакого диалога с ошибкой — запрос на проверку просто не срабатывает, и PR вливается без нужного контроля.
Это руководство поможет быстро настроить всё правильно, а основное внимание уделяет типичным ловушкам: правилу «побеждает последнее совпадение», которое незаметно перекрывает ваши конкретные правила, а также сбоям из-за прав доступа, пустых команд и настроек ветки по умолчанию, из-за которых CODEOWNERS выглядит настроенным, но ничего не делает.
Ключевые выводы
- В CODEOWNERS действует принцип «побеждает последнее совпадение»: если несколько шаблонов соответствуют файлу, владельцев назначает только последняя подходящая строка — размещайте общие правила вверху, а конкретные переопределения внизу.
- Файл должен находиться в базовой ветке PR, занимать не более 3 МБ, использовать правильный регистр символов и корректный синтаксис; любая строка с ошибкой молча пропускается.
- CODEOWNERS сам по себе не блокирует слияния — необходимо также включить параметры «Require a pull request before merging» и «Require review from Code Owners» в наборе правил или правиле защиты ветки.
- Владелец без прав на запись молча игнорируется, а команда-владелец должна быть видимой и иметь права на запись, даже если каждый её участник уже имеет такие права.
- GitHub CODEOWNERS не поддерживает отрицание через
!— шаблоны вида!README.mdсчитаются недопустимыми.
Что делает файл CODEOWNERS?
CODEOWNERS назначает ответственных за конкретные пути в репозитории — отдельных пользователей или команды. Когда кто-то открывает pull request, изменяющий соответствующий путь, GitHub автоматически запрашивает проверку у указанных владельцев. Тот же формат файла работает на GitHub, GitLab и Bitbucket; примеры здесь ориентированы прежде всего на GitHub.
По мере того как всё большая доля PR создаётся ИИ-агентами, правило CODEOWNERS для чувствительных путей — auth/, **/migrations/, конфигурация CI — гарантирует, что человек-владелец всё равно проверит изменения агента перед их принятием.
Discover how at OpenReplay.com.
Как настроить и применить CODEOWNERS?
Разместите файл по пути .github/CODEOWNERS. GitHub ищет его сначала в .github/, затем в корне репозитория, затем в docs/ и использует первый найденный CODEOWNERS — единственное каноническое расположение исключает путаницу. Записывайте по одному правилу на строку в формате шаблон @владелец, затем зафиксируйте файл в ветке по умолчанию.
# .github/CODEOWNERS
# Владельцы по умолчанию для всего репозитория
* @my-org/core-team
# Frontend и backend по областям
/src/frontend/ @my-org/frontend-team
/src/backend/ @my-org/backend-team
# Тесты и документация
**/tests/ @my-org/qa-team
*.md @my-org/docs-team
# Чувствительные пути получают выделенного владельца (размещайте их последними)
/src/auth/ @my-org/security-team
Добавьте файл как любой другой:
git add .github/CODEOWNERS
git commit -m "Add CODEOWNERS"
git push origin main
Фиксация файла только запрашивает проверяющих — она ничего не блокирует. Чтобы реально ограничить слияния, необходимо одновременно включить два параметра: Require a pull request before merging и Require review from Code Owners. Их можно настроить в новых Rulesets (Settings → Rules → Rulesets) или в классическом правиле защиты ветки (Settings → Branches). Оба варианта актуальны; Rulesets — более новый интерфейс.
Полезные синтаксические шаблоны CODEOWNERS
Язык шаблонов следует большинству правил gitignore. Эти пять охватывают почти всё:
* @core-team # глобальное значение по умолчанию
/api/ @backend-team # директория
*.ts @frontend-team # расширение на любой глубине
**/tests/ @qa-team # вложенная директория в любом месте
/security/ @sec-team @compliance-team # два владельца на одной строке
Неприкреплённый glob расширения вида *.ts соответствует файлам этого типа в любом месте репозитория — он ведёт себя так же, как **/*.ts. Важно одно правило при перечислении нескольких владельцев: все они должны быть указаны на одной строке. Если разбить их по разным строкам, шаблон назначит только последнего упомянутого владельца. Когда требуется проверка от владельцев кода, для выполнения требования достаточно одобрения любого одного из перечисленных.
Развеем один миф: в отличие от .gitignore, GitHub CODEOWNERS не поддерживает отрицание через !. Шаблоны вида !README.md считаются недопустимыми — официальная документация GitHub прямо указывает, что !, диапазоны символов [ ] и экранирование \# являются возможностями gitignore, которые здесь не работают. Чтобы исключить путь, назначьте ему другого владельца или выстройте правила так, чтобы ни одно из них не совпадало с ним (если оставить столбец владельца пустым в более позднем, более конкретном правиле, это снимет владение для данного пути).
Правило «побеждает последнее совпадение» (ошибка №1)
В CODEOWNERS действует принцип «побеждает последнее совпадение»: если несколько шаблонов соответствуют файлу, владельцев назначает только последняя подходящая строка. Порядок правил — самая распространённая причина сбоев. Размещайте общие правила вверху, а конкретные переопределения внизу.
Вот неправильный порядок — маска-перехватчик стоит последней и молча забирает всё:
# НЕПРАВИЛЬНО — * стоит последним, поэтому @core-team владеет и /src/auth/
/src/auth/ @security-team
* @core-team
Поскольку * соответствует /src/auth/app.ts и стоит позже в файле, @security-team никогда не запрашивается. Поменяйте порядок:
# ПРАВИЛЬНО — сначала общее, конкретное переопределение в конце
* @core-team
/src/auth/ @security-team
Теперь изменение в /src/auth/ запросит @security-team, а всё остальное перейдёт к @core-team. Проверяйте порядок шаблонов каждый раз, когда добавляете новое правило.
Почему CODEOWNERS молча не срабатывает
Большинство случаев «настроено, но ничего не происходит» объясняются одной из следующих причин. CODEOWNERS читается из базовой ветки pull request, чувствителен к регистру, должен занимать не более 3 МБ и пропускает любую строку с недопустимым синтаксисом — поэтому файл, который выглядит корректным, может не запросить ни одной проверки.
| Симптом | Причина | Решение |
|---|---|---|
| Проверяющий не запрашивается вообще | Файл отсутствует в базовой ветке PR | Зафиксируйте CODEOWNERS в ветке, в которую выполняется слияние |
| Конкретное правило никогда не срабатывает | Последнее совпадение побеждает — более позднее правило его перекрывает | Переместите общие правила вверх, конкретные — вниз |
| Одна строка игнорируется, остальные работают | Недопустимый синтаксис в этой строке — она молча пропускается | Откройте файл на GitHub; ссылка «Syntax errors» укажет на проблемные строки |
| Владелец указан, но не запрашивается | У владельца нет прав на запись или пользователь/команда не существует | Предоставьте права на запись; проверьте корректность имени |
| Слияние заблокировано, никто не может одобрить | Пустая команда владеет этим путём | Добавьте хотя бы одного участника в команду |
| Путь ни с чем не совпадает | Ни одно правило его не охватывает | Добавьте правило или примите одобрение от любого пользователя с правами на запись |
| Запрос не создаётся для черновика PR | Черновые PR не инициируют запросы владельцев кода | Пометьте PR как готовый к проверке |
| Правило игнорируется для большого файла | CODEOWNERS объёмом более 3 МБ не загружается | Объедините записи с помощью подстановочных знаков |
Два нюанса с правами доступа вызывают большинство тихих сбоев. Люди, назначенные владельцами кода, должны иметь права на запись — владелец без таких прав молча игнорируется. Когда владельцем является команда, она сама должна быть видимой и иметь права на запись, даже если каждый её участник уже имеет права на запись индивидуально. Если указать пользователя или команду, которые не существуют или не имеют доступа, владелец кода не назначается — без каких-либо предупреждений в PR. GitHub всё же отображает проблемные строки: откройте файл CODEOWNERS в интерфейсе репозитория, чтобы увидеть выделенные ошибки, которые также доступны через REST API.
Помимо статического назначения: автоназначение в командах и Actions
CODEOWNERS статически сопоставляет пути с владельцами. Два механизма расширяют его возможности, когда этого недостаточно.
Встроенное автоназначение в команде избавляет от необходимости упоминать всю команду. В разделе Organization → Teams → команда → Settings → Code review включите автоназначение: каждый раз, когда запрашивается команда, запрос к ней снимается и вместо этого назначается подмножество участников. Выберите round robin — ротация по принципу наименее недавнего запроса — или load balance, выравнивающий общее количество недавних запросов для каждого участника. Обратите внимание на один нюанс: когда владелец кода требуется по правилу защиты ветки, запрос к команде не может быть снят, поэтому индивидуальный запрос добавляется в дополнение к командному.
Используйте GitHub Actions только тогда, когда назначение должно зависеть от содержимого diff или метки — того, что CODEOWNERS не может выразить. Минимальный рабочий процесс с использованием actions/checkout (последняя версия v7.0.0, выпущена 18 июня 2026 г.) и action для назначения проверяющих на обычный триггер pull_request:
name: Assign Reviewers
on:
pull_request:
types: [opened, ready_for_review]
permissions:
pull-requests: write
jobs:
assign:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0 # необходимо для git diff между ветками
# ...здесь сопоставляйте изменённые пути или метки с проверяющими
Используйте следующую иерархию как руководство к действию, а не как меню: CODEOWNERS — для статических правил «путь → владелец», автоназначение в команде — для распределения нагрузки внутри команды, Actions — для логики на основе изменений или меток.
Начните с одного файла .github/CODEOWNERS в ветке по умолчанию, выстройте его от общего к частному, включите «Require review from Code Owners», затем откройте тестовый PR и убедитесь, что ожидаемый владелец запрошен — эта единственная проверка выявит тихие сбои до того, как они попадут в продакшн.
Часто задаваемые вопросы
В чём разница между CODEOWNERS и автоназначением проверки кода в командах GitHub?
CODEOWNERS — это статический файл, сопоставляющий шаблоны путей с владельцами и запрашивающий проверку каждый раз, когда PR затрагивает соответствующий путь. Автоназначение в команде — это настройка на уровне организации, которая при запросе к команде заменяет запрос ко всей команде запросом к подмножеству участников, выбранных по принципу round robin или load balance. Они работают совместно: CODEOWNERS определяет, какая команда владеет путём, а автоназначение решает, кто из участников этой команды получит уведомление.
Можно ли исключить конкретный файл из правила CODEOWNERS с помощью отрицания, как в gitignore?
Нет. GitHub CODEOWNERS не поддерживает отрицание, поэтому шаблон вида '!README.md' считается недопустимым, и строка молча пропускается. Документация GitHub прямо указывает, что отрицание через '!', диапазоны символов '[ ]' и экранирование '#' являются возможностями gitignore, которые здесь не работают. Чтобы исключить путь, добавьте более позднее, более конкретное правило, назначающее ему другого владельца, или оставьте столбец владельца пустым в этой конкретной строке, чтобы снять владение для данного пути.
Почему владельцы кода не запрашиваются в моём pull request, хотя файл выглядит корректным?
Наиболее распространённая причина в том, что CODEOWNERS читается из базовой ветки PR, поэтому файл, присутствующий только в вашей feature-ветке, никогда не сработает. Другие тихие причины: у владельца нет прав на запись, команда-владелец невидима или не имеет прав на запись, команда пуста, PR является черновиком (черновые PR никогда не инициируют запросы владельцев кода), файл превышает 3 МБ, пути указаны в неправильном регистре или строка содержит недопустимый синтаксис, который GitHub пропускает без предупреждения.
Блокирует ли CODEOWNERS слияния самостоятельно, или нужна защита ветки?
CODEOWNERS сам по себе только запрашивает проверяющих и никогда не блокирует слияние. Чтобы ограничить слияния, необходимо также включить два параметра одновременно: 'Require a pull request before merging' и 'Require review from Code Owners'. Настройте их в наборе правил в разделе Settings, Rules, Rulesets или в классическом правиле защиты ветки в разделе Settings, Branches. Оба варианта актуальны, при этом Rulesets является более новым интерфейсом.