# Git Monorepo Release

> Ведёт релиз монорепо с несколькими независимо версионируемыми пакетами или SDK (sdk-go, sdk-java, sdk-python, sdk-csharp): решает, какие пакеты затронуты, какой bump нужен каждому, и какие теги вида `sdk-go/vX.Y.Z` ставятся одновременно. Умеет backport patch'а в старую версию через release-ветку и cherry-pick. Используй, когда в репозитории несколько версионируемых пакетов и пользователь говорит «релиз монорепо», «затегать несколько SDK», «какие пакеты бампить», «выпустить sdk-go и sdk-python», «бэкпортнуть фикс в v0.1». Для релиза одного пакета в обычном репозитории — `git-release-tag`, не этот скилл.

- Skill: `jtprogru/git-monorepo-release` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add jtprogru/git-monorepo-release`
- Raw SKILL.md: https://api.skillmd.com/api/skills/jtprogru/git-monorepo-release/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: jtprogru (https://skillmd.com/u/jtprogru)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/jtprogru/git-monorepo-release

---


<!-- СГЕНЕРИРОВАНО bin/mirror.js. Не редактировать: правки затрёт следующая генерация.
     Источник правды — domains/<домен>/. -->

# git-monorepo-release — Релиз монорепо с независимыми версиями

Цель: в репозитории, где живёт несколько пакетов со своими версиями, определить состав релиза и провести его так, чтобы версии не поехали друг относительно друга.

Перед началом прочитай `../../rules/git-conventions.md` — разделы про Semver и теги.

Постановку одного тега с changelog делает **`git-release-tag`**. Этот скилл решает, *какие* теги ставить и *почему*, и вызывает `git-release-tag` на каждый.

## Границы

Скилл применим, когда в репозитории **больше одного независимо версионируемого пакета**. Проверь это до всего остального:

```bash
git tag --list --sort=-v:refname | head -20
ls -d */ | head -20
```

Признаки монорепо с независимыми версиями: теги вида `<name>/vX.Y.Z`, несколько директорий с собственными манифестами (`go.mod`, `package.json`, `pyproject.toml`, `*.csproj`).

Если пакет один — скажи об этом и передай работу `git-release-tag`. Не изобретай монорепо там, где его нет.

## Шаг 1. Определи затронутые пакеты

Возьми диапазон с последнего релиза каждого пакета и посмотри, что реально менялось:

```bash
# последний тег конкретного пакета
git tag --list 'sdk-go/v*' --sort=-v:refname | head -1

# что изменилось в его директории с тех пор
git log sdk-go/v0.3.0..HEAD --oneline -- sdk-go/
```

Пройди так по каждому пакету. Пакет без коммитов в своей директории **не релизится** — даже если релизится соседний.

Осторожно с изменениями вне директорий пакетов: правка общей спецификации, protobuf-схемы или генератора может затрагивать всех потребителей, не оставив коммитов в их папках. Такие коммиты покажи пользователю отдельно и спроси, чьи версии они двигают.

## Шаг 2. Определи bump для каждого пакета

Semver считается для каждого пакета **отдельно**. Breaking change в Go SDK не двигает версию Python SDK.

| изменение | что бампить |
|---|---|
| только спецификация, реализации не тронуты | ничего — до момента реализации в пакетах |
| баг в одном пакете | только его, patch |
| фича, реализованная в нескольких пакетах | каждый затронутый, отдельным тегом, minor |
| breaking change в пакете версии < 1.0 | только его, minor |
| breaking change в пакете версии ≥ 1.0 | только его, major |

Правило нулевой мажорной версии: до `v1.0.0` breaking change идёт в minor, а не в major. Пакеты в монорепо часто находятся на разных стадиях зрелости, поэтому проверяй текущую версию каждого, а не применяй одно правило ко всем.

Если коммиты не по Conventional Commits и bump не выводится — покажи их пользователю и спроси. Не угадывай.

## Шаг 3. Покажи план релиза целиком

До любых команд покажи таблицу и дождись подтверждения:

```
Пакет         текущая   новая     причина
sdk-go        v0.3.0  → v0.4.0    feat(sdk-go): streaming API
sdk-python    v0.2.1  → v0.2.2    fix(sdk-python): retry on 429
sdk-java      v0.5.0    —         нет изменений
sdk-csharp    v0.1.2    —         нет изменений
```

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

## Шаг 4. Проведи релиз

Для каждого релизуемого пакета вызови **`git-release-tag`** — он соберёт changelog из коммитов и поставит annotated-тег.

Теги ставятся на один и тот же коммит `main`, поэтому сначала убедись, что дерево чистое и main актуален:

```bash
git checkout main && git pull --ff-only
git status --porcelain      # должно быть пусто
```

Пуш нескольких тегов — одной командой, чтобы CI увидел релиз целиком, а не по частям:

```bash
git push origin sdk-go/v0.4.0 sdk-python/v0.2.2
```

Не пушь без явного подтверждения. Тег, за который зацепился release-pipeline, откатывается тяжело.

## Шаг 5. GitHub Releases

Один Release на один тег. Каждый содержит changelog **только своего пакета** — не сваливай изменения всех SDK в общий текст.

```bash
gh release create sdk-go/v0.4.0 --title "sdk-go v0.4.0" --notes-file <changelog>
```

Если CI уже создаёт Releases по тегу — не дублируй вручную, просто запушь тег и скажи об этом пользователю.

## Backport в старую версию

Когда часть пользователей осталась на старой версии, а main ушёл вперёд:

```bash
# ветка от старого тега
git checkout -b release/sdk-go-v0.1 sdk-go/v0.1.0

# только нужный фикс
git cherry-pick <commit-sha>

# patch поверх старой линии
git tag -a sdk-go/v0.1.1 -m "sdk-go v0.1.1"
git push origin release/sdk-go-v0.1 sdk-go/v0.1.1
```

Release-ветку заводи только когда backport действительно нужен. В обычной ситуации фикс едет в main и выходит следующим minor.

После backport проверь, что фикс есть и в main — иначе следующий релиз его потеряет.

## Почему формат тега именно такой

`<пакет>/vX.Y.Z` — не стилистический выбор. Go требует ровно такой формат, чтобы `go get` умел забрать модуль из поддиректории монорепо: путь тега должен совпадать с путём модуля относительно корня репозитория. Для единообразия остальные пакеты используют тот же формат, хотя их тулчейны свободнее.

Отсюда следует: не ставь общий тег `vX.Y.Z` на монорепо с независимыми версиями. Он не соответствует ни одному пакету и ломает разрешение версий у Go.

## Чего не делать

- не ставь общий тег на все пакеты сразу — версии разъедутся, а Go перестанет находить модуль
- не бампь пакет, в котором нет изменений, ради «ровных» номеров
- не переиспользуй и не передвигай опубликованный тег: пользователи уже получили этот код под этой версией
- не выводи major из `feat!` вслепую — сначала посмотри, дошёл ли пакет до 1.0
- не релизь при грязном рабочем дереве: тег укажет на коммит, которого нет у остальных

