Инженерия

Changelog монорепозитория: один, или по одному на пакет?

4 мин чтения

Монорепозиторий вмещает несколько отдельно выпускаемых вещей в одном репозитории, и changelog должен сначала ответить на вопрос: читателю важен репозиторий или конкретный пакет внутри него? Большинство команд никогда не решают это осознанно. Они начинают с одного changelog, потому что есть один репозиторий, добавляют пакеты со временем и заканчивают журналом, где пользователю CLI приходится пролистывать сорок несвязанных записей бэкенда, чтобы найти ту, что выпустила его исправление. Правильную форму определяет не структура репозитория, а то, кто читает журнал и что он уже знает искать.

Чем changelog монорепозитория отличается от changelog единого репозитория?

У changelog единого репозитория есть подразумеваемая аудитория — все, кто пользуется единственной вещью, которую строит этот репозиторий. Аудитория монорепозитория делится по пакетам, и пакеты в одном репозитории часто выпускаются по разным графикам, для разных потребителей, на разных уровнях стабильности. Библиотека, опубликованная в реестре, и внутренний административный инструмент могут жить в одном монорепозитории и почти не иметь ничего общего для читателя changelog.

Форма репозиторияТипичный читательПодходящий changelog
Одно выпускаемое приложениеВсе, кто пользуется продуктомОдин журнал, для всего репо
Workspace библиотек (несколько публикуемых пакетов)Кто зависит от конкретного пакетаОдин журнал на пакет
Приложение плюс внутренние инструментыДве разные аудитории без пересеченияРазделено по аудитории, не по папке
Приложение плюс собственный SDKПользователи продукта и интеграторы SDKДва журнала: для продукта, для SDK

Нужен ли каждому пакету собственный changelog?

Только тем, у кого независимая аудитория. Пакету, публикуемому в реестре, нужен собственный журнал, потому что у устанавливающего его человека нет причин читать что-то ещё в репозитории, а инструменты релиза для монорепозиториев, такие как Lerna и Changesets, пишут CHANGELOG.md для каждого пакета рядом с его package.json. Внутренней утилите с одним потребителем — приложением, уже живущим в том же репозитории, — отдельный журнал не нужен; включение её изменений в записи этого приложения полезнее второго файла, который никто за пределами команды не открывает.

Тест тот же, что решает, принадлежит ли вообще какая-то запись changelog: заметит ли читатель это или это его волнует, и может ли он действовать, зная это. Применяй его по пакету, не по папке, и репозиторий с двенадцатью пакетами может закончиться двумя настоящими changelog и десятью пакетами, которым он просто не нужен.

Как узнать, какой пакет вызвал какую запись changelog?

Помечай каждую запись её пакетом в момент написания, а не позже, изучая, какие файлы затронул коммит. Коммит, исправляющий общую внутреннюю библиотеку, может породить запись changelog в каждом пакете, зависящем от неё, и одни пути файлов не скажут, какую из этих нижестоящих записей читателю действительно нужно увидеть; это может решить только человек, определяющий “это видно пользователю пакета A и не видно пользователю пакета B”. Conventional commits помогают здесь механически, называя пакет в каждом коммите, но scope всё равно даёт лишь черновик. То же правило двух слоёв из той статьи применяется по пакету: черновик с правильным scope всё равно нуждается в человеческом проходе, прежде чем он сформулирован для реального читателя этого пакета.

Что нужно общему changelog, чего не нужно changelog единого репозитория?

Метка пакета на каждой записи, в самом начале, перед описанием, чтобы читатель, просматривающий журнал, мог за один проход пропустить всё, что не его. Без этой метки общий журнал читается как случайная лента, и читателю, интересующемуся одним пакетом, некак его отфильтровать, кроме как запоминать, какие строки важны, чего никто не делает после первой недели.

## 2026-09-07

### [cli] Добавлено
- `acme push --dry-run` показывает, что было бы отправлено,
  не отправляя это на самом деле.

### [core] Исправлено
- Backoff повторных попыток больше не сбрасывается при успешном
  запросе, возвращающем пустое тело.

Две записи, две аудитории, один взгляд, чтобы их различить. Рабочий процесс в стиле Changesets встраивает эту маркировку прямо в процесс релиза: контрибьютор пишет короткую заметку со scope пакета рядом со своим изменением, а инструмент собирает changelog по пакетам и скачки версий из этих заметок в момент релиза, вместо попытки восстановить границы пакетов постфактум из объединённой истории коммитов.

Как версионирование связано с changelog монорепозитория?

Независимо версионируемым пакетам нужен собственный changelog, потому что у них собственный номер версии, и общий changelog не может выразить “пакет A перешёл с 2.1 на 2.2, пока пакет B остался на 1.4”, не превратившись в два журнала внутри одного файла. Semantic versioning и ваш changelog разбирает, как номер версии должен маппиться на категории changelog; в монорепозитории это соответствие нужно применять по пакету, потому что breaking change в одном пакете не является breaking change для соседнего пакета, который от него не зависит.

Репозиторий, выпускающий один продукт как единую выпускаемую единицу, даже если он собран из множества внутренних пакетов, не сталкивается с этой проблемой: пакеты делят версию, потому что всегда выпускаются вместе, и единый changelog — правильное решение.

Как git-теги вписываются в монорепозиторий?

То же правило из git-тегов, релизов и вашего changelog применяется по пакету: пакету с собственной версией нужен собственный префикс тега, обычно имя-пакета@1.4.0 вместо голого v1.4.0, который не может сказать, какому пакету он принадлежит. Монорепозиторий, помеченный только голыми номерами версий, не может позже ответить “что было в core, когда cli выпустил 2.2”, потому что ничто на диске не фиксирует, какому пакету на самом деле принадлежал этот тег.

FAQ

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

Что помечает запись changelog правильным пакетом? Человек, пишущий запись, в момент её написания, а не автоматическое сканирование изменённых путей файлов. Изменение в общей библиотеке может породить разную запись в каждом зависящем от неё пакете, и только человек может решить, что на самом деле должна говорить каждая из этих нижестоящих записей.

Стоит ли монорепозиторию использовать один номер версии для всего? Только если каждый пакет всегда выпускается вместе с остальными. Если пакеты когда-либо публикуются независимо, им нужны независимые версии, а независимым версиям нужны независимые changelog, чтобы иметь смысл.

Заменяет ли инструмент changelog для монорепозитория этап человеческого редактирования? Нет. Инструменты вроде Changesets автоматизируют сбор и сборку заметок по пакетам в момент релиза; сама заметка, написанная на языке читателя, а не контрибьютора, остаётся работой человека, как и в любом другом pipeline changelog.


Технические утверждения в этой статье не проходили независимую проверку. Если здесь что-то не так, сообщите нам, и мы исправим.

По теме на changeloop: Генератор changelog, Документация для разработчиков

changeloop
Команда, которая делает changelog, замыкающий цикл. Пользователи о чём-то просят, ваша команда это делает, тот, кто просил, узнаёт об этом.