@@ -160,8 +160,24 @@ T-Bank. Полные команды и ограничения принадлеж
`main` хранит принятые релизы, `develop` — интеграцию разработки. Новая задача:
отдельная [issue-linked ветка ](.ai/conventions/engineering-workflow.md#git-branching )
от свежего `develop` , затем PR в `develop` .
В `main` напрямую не пушить. Обычные PR можно squash-merge; релизные PR и
обратную синхронизацию `main` с `develop` сливать с сохранением истории.
В `main` напрямую не пушить. Рабочие PR сливать squash или rebase-merge;
merge-коммиты запрещены. `main` получает изменения только fast-forward из
`develop` , поэтому история обеих веток линейна:
``` text
<type>/<issue>-<slug> --squash--> develop --ff-only--> main --> tag vX.Y.Z
```
Инвариант: `origin/main` всегда предок `origin/develop` . Проверка в любом repo:
``` bash
git fetch -q origin
git merge-base --is-ancestor origin/main origin/develop && echo ok || echo BROKEN
```
Инвариант нарушается только осознанным исключением
([Ограничения модели ](#ограничения-модели )); после него `develop` возвращают
в согласованное состояние до следующего релиза.
Commits и заголовки PR — Conventional Commits. `feat:` повышает minor,
`fix:` /`perf:` — patch, `!` или `BREAKING CHANGE:` — major, в том числе до 1.0.
@@ -174,8 +190,8 @@ Commits и заголовки PR — Conventional Commits. `feat:` повыша
### Подготовка релиза
1. Обновить `main` , `develop` и теги командой `git fetch origin --tags` .
Проверить, что текущий `develop` содержит последний релиз из `main `.
Создать `release/<name>` от проверенного `develop` и выполнить `npm ci` .
Проверить инвариант. Создать `release/X.Y.Z` от проверенного `develop `
и выполнить `npm ci` .
2. Проверить локальные входы и публичные artifacts выпускаемого репозитория.
Совместимость развёрнутых участников согласовать отдельно через публичные
контракты; CI не скачивает соседние checkout и не требует их SHA.
@@ -186,19 +202,20 @@ Commits и заголовки PR — Conventional Commits. `feat:` повыша
наличие коммитов. Теги и соответствие версии последнему принятому тегу
проверяются вручную; уже подготовленную версию повторно не повышать.
4. Проверить diff релизного коммита и штатные gates. Отправить только релизную
ветку: `git push -u origin HEAD` . Открыть PR в `main` с заголовком
ветку: `git push -u origin HEAD` . Открыть PR в * * `develop` ** с заголовком
`chore(release): X.Y.Z` . После зелёных обязательных проверок (`commits` в root;
`verify` , `security` , `commits` в остальных repo)
выполнить **fast-forward-only merge ** . Если `main ` изменился, сначала
согласовать историю и повторить проверку кандидата; не обходить защиту.
5. После merge получить `main` и убедиться, что его HEAD — проверенный релизный
коммит, версия и lockfile совпадают. На этом SHA создать аннотированный тег:
выполнить **fast-forward-only merge ** . Если `develop ` изменился, обновить
релизную ветку и повторить проверку кандидата; не обходить защиту.
5. Открыть PR `develop → main` с тем же заголовком и слить
**fast-forward-only ** . `main` получает ровно проверенный релизный коммит;
merge-коммит здесь невозможен по определению ff.
6. Получить `main` и убедиться, что его HEAD — проверенный релизный коммит,
версия и lockfile совпадают. На этом SHA создать аннотированный тег:
`git tag -a vX.Y.Z <release-sha> -m "Release X.Y.Z"` , затем отправить
только этот тег: `git push origin refs/tags/vX.Y.Z` . Повторно release-it
на `main` не запускать: он уже подготовил версию.
6. Через PR `main → develop` вернуть релизный коммит в разработку без squash
и rebase. Убедиться, что `develop` содержит тег. После первого выпуска
`develop` создаётся непосредственно от релизного SHA.
на `main` не запускать: он уже подготовил версию. Обратная синхронизация
не нужна: релизный коммит попал в `develop` на шаге 4.
Перед публикацией тегов сравнить local SHA с удалённым `main` ; PR и проверки
должны относиться к этому кандидату. Опубликованные теги не перемещать.
@@ -212,11 +229,20 @@ Commits и заголовки PR — Conventional Commits. `feat:` повыша
Исторические неконвенциональные commits не переписываются; первый changelog
требует просмотра человеком. Дальнейшие версии выбираются по commits.
### Hotfix, проверки и защита
### Ограничения модели
Срочный fix начинается от `main` , проходит проверки и релизный PR из
`release/hotfix-<name>` в `main` , затем обязательно возвращается в `develop` .
Если ломается публичный контракт, major сохраняется и для hotfix.
Freeze релиза не поддерживается: кандидат нельзя заморозить и параллельно
принимать работу в `develop` . Пока открыт релизный PR, `develop` не двигают .
Срочный fix — обычная ветка `fix/<issue>-<slug>` от `develop` с последующим
релизом. Отдельного пути от `main` нет: он сделал бы `main` не-предком
`develop` и заблокировал следующий ff. Если `develop` содержит незаконченную
работу, быстрого фикса нет — это цена отказа от release-ветки в `main` .
Исключение требует явного решения: `release/hotfix-<name>` от `main` ,
PR в `main` , тег, затем merge `main → develop` для восстановления инварианта.
Такой релиз оставляет merge-коммит в `develop` ; cherry-pick из `develop`
в hotfix-ветку порождает дубль коммита при последующем rebase и не
применяется. Если ломается публичный контракт, major сохраняется и для hotfix.
Каждый CI использует только свой checkout. Backend генерирует OpenAPI без сервера,
сверяет генератор с configured app и не хранит JSON в Git; frontend проверяет types по входному
@@ -227,12 +253,17 @@ snapshot. Docs проверяет внутренние ссылки; внешн
доступ к root для выпуска другого репозитория не требуется.
В Gitea для `main` и `develop` нужны запрет прямого push и force-push,
обязательные проверки: в root только `commits` , в остальных repo —
`verify` , `security` , `commits` ; также нужен запрет обхода правил
администратором. Требование отдельного одобрения review не вводится для
разработки одним владельцем. Ветка по умолчанию — `develop` ; Renovate тоже
отправляет PR в `develop` . Теги `v*` защищены, создание разрешается владельцу
релиза; их удаление или перенос не входит в обычный процесс.
блокировка устаревшей ветки перед merge, обязательные проверки: в root только
`commits` , в остальных repo — `verify` , `security` , `commits` ; также нужен
запрет обхода правил администратором. Требование отдельного одобрения review
не вводится для разработки одним владельцем. Ветка по умолчанию — `develop` ;
Renovate тоже отправляет PR в `develop` . Теги `v*` защищены, создание
разрешается владельцу релиза; их удаление или перенос не входит в обычный процесс.
Линейность истории Gitea отдельной опцией не выражает, её обеспечивают
разрешённые merge styles репозитория: merge-коммиты и rebase с `--no-ff`
выключены, доступны squash, rebase-merge и fast-forward-only. Стиль по
умолчанию — squash, обновление ветки — rebase, ветка после merge удаляется.
В root нет собственного test/verify runner и release hooks. Release-it и
commitlint используются напрямую. Остальные репозитории сохраняют свои gates.