Changelog
Changelog — це впорядкований, зрозумілий людині запис того, що змінилося в кожному релізі. Уся його цінність — у тому, що він написаний для читача, який вирішує, чи оновлюватися. Саме тому згенероване звалище комітів, хай навіть повне, не є changelog. На цій сторінці — шість заголовків, що обіцяє номер версії, депрекація і як далеко чесно може завести автоматизація.
- Написаний для
- Людей, не інструментів
- Схема версій
- MAJOR.MINOR.PATCH
- Конвенція
- Keep a Changelog
Git log — це не changelog
Історія комітів фіксує, що робила команда, у порядку подій і власною термінологією команди. Changelog фіксує, що змінилося для того, хто користується софтом, згруповано за значущістю. Це різні документи для різних аудиторій, і генерація одного з іншого без редагування дає щось технічно точне й практично нечитабельне.
Запис у changelog
- Cookie сесії тепер живуть 30 днів замість 7
- Виправлено збій експорту для файлів понад 50 МБ
- Видалено ендпоінт пошуку v1 — використовуйте /v2/search
Повідомлення коміту
- fix: bump TTL constant
- chore: refactor stream handler
- feat: drop legacy route
- Merge branch develop into main
Прочитайте праву колонку очима користувача софту. Жоден запис не каже, чи треба вам щось робити, — а останній не каже взагалі нічого.
Три документи, які плутають
Значна частина поганих changelog — це один файл, що намагається бути трьома. Changelog повний і стислий: кожна зміна, по рядку на кожну, для читача, що вирішує, чи оновлюватися. Реліз-ноти вибіркові й рекламні: три речі, варті анонсу, для того, хто не стежив. Гайд з міграції інструктивний: для кожної ламкої зміни — старий код і новий, для того, хто саме посеред оновлення, яке щойно впало.
У них різна довжина, різний тон і різна тривалість життя, а спроба вдовольнити всі три одразу дає документ, задовгий для перегляду й заповерхневий для дій. Замість цього — посилайтеся: рядок changelog називає ламку зміну й веде на розділ гайду з міграції, що її пояснює.
Номер версії — це обіцянка
Semantic Versioning перетворює три числа на контракт сумісності. Річ не в охайності, а в тому, що читач може вирішити, чи безпечне оновлення, не читаючи diff, а менеджер залежностей може вирішити це замість нього.
Правило, на якому все тримається: якщо наявним користувачам треба щось змінити, щоб усе далі працювало, це підняття MAJOR — незалежно від того, наскільки дрібною зміна здається зсередини. Перейменування поля, суворіша валідація, перетворення необов’язкового параметра на обов’язковий і прибирання значення за замовчуванням — усе це ламкі зміни, і випуск їх патчем є тим, як залежність заробляє собі репутацію.
Нуль, пререлізи та метадані збірки
Усе, що починається з 0., явно поза обіцянкою: під час 0.y.z специфікація каже, що будь-що може змінитися будь-коли. Це чесно, поки дизайн ще рухається, і нечесно, коли від нього залежать реальні користувачі. Проєкт, що чотири роки сидить на 0.x зі споживачами в production, використовує нуль як спосіб уникнути зобов’язання, а не як сигнал нестабільності.
Пререліз позначають дефісом — 2.0.0-rc.1 — і він сортується перед релізом, якому передує, тож менеджер залежностей, що просить 2.0.0, не візьме його випадково. Метадані збірки позначають плюсом — 2.0.0+build.482 — і при порівнянні версій їх повністю ігнорують, тож це правильне місце для хешу коміту й неправильне для будь-чого, що користувачеві треба знати.
Що містить хороший запис
Конвенція Keep a Changelog групує кожен реліз під шістьма заголовками. Однакові шість скрізь означають, що читач може одразу шукати потрібний — найчастіше це Removed і Changed, бо саме вони створюють роботу.
| Заголовок | Для чого | Читач питає |
|---|---|---|
| Added | Нові можливості | Чи з’явилося щось, що я тепер можу? |
| Changed | Наявна поведінка, що змінилася | Чи поводитиметься моє поточне використання інакше? |
| Deprecated | Ще працює, буде видалено | З чого і до якого часу треба мігрувати? |
| Removed | Зникло в цій версії | Що зламається одразу після оновлення? |
| Fixed | Виправлені дефекти | Чи потрібен ще мій обхідний шлях? |
| Security | Усунені вразливості | Чи треба оновлюватися терміново? |
Решта конвенції механічна, і її варто дотримуватися точно, бо саме вона дозволяє читачеві щось знайти. Найновіша версія — угорі. Один розділ на випущену версію з датою за ISO — 2026-08-19, а не 19/08/26, що означає різне залежно від країни читача. Розділ Unreleased над усіма. І примітка, якої схеми версіонування дотримується проєкт, щоб ніхто не вгадував, що означає підняття minor.
Дві звички роблять більшу частину решти роботи: наповнюйте розділ Unreleased у міру появи змін, щоб записи писалися, поки зміна свіжа, і формулюйте кожен рядок як наслідок для користувача, а не як правку в коді. Changelog, зібраний напередодні релізу, завжди виходить худим, бо той, хто його збирає, відновлює місяць за темами комітів.
Депрекація — те, що купує довіру
Removed — заголовок, що створює роботу; Deprecated — заголовок, що дає час її зробити. Депрекація — це обіцянка з трьох частин, а повідомлення про депрекацію без якоїсь із них є просто скаргою на власний код.
- Що зникає — названо достатньо точно, щоб читач міг пошукати це у власному коді.
- Що використовувати натомість — і заміна вже доступна, а не обіцяна на потім.
- Коли це буде прибрано — вказано версією, а не порою року.
Робоча політика вміщається в рядок: усе, що задепрековано в minor-релізі, прибирається не раніше наступного major і ніколи між ними. Опублікуйте це одного разу — і кожне повідомлення про депрекацію це успадкує. Ціна — нести мертвий код один цикл; віддача — оновлення вашого софту перестає бути тим, що відкладають, а це різниця між залежністю, яку тримають свіжою, і тією, що тихо форкається в шести організаціях.
Як далеко чесно заходить автоматизація
Conventional Commits стандартизує тему коміту так, щоб її міг прочитати інструмент: тип, необов’язкова область, необов’язковий знак оклику для ламкої зміни, далі опис — «feat(auth): accept refresh tokens», «fix!: reject unsigned webhooks». Ламку зміну можна також оголосити у футері, що починається з «BREAKING CHANGE:», і це краще місце, коли потрібне речення пояснення.
| Коміт | Означає | Потрапляє під |
|---|---|---|
| fix: | Підняття PATCH | Fixed |
| feat: | Підняття MINOR | Added |
| ! або BREAKING CHANGE: | Підняття MAJOR | Changed або Removed |
| chore:, docs:, refactor: | Без підняття | Зазвичай нікуди — немає видимого ефекту |
Це справді допомагає: інструмент може вивести наступний номер версії й зібрати чернетку, згруповану під правильними заголовками, — а це два найнудніші кроки. Чого він не може — вирішити, чи є зміна ламкою, бо це залежить від того, як люди насправді користуються продуктом, а це знання живе поза репозиторієм. Коміт із міткою fix:, що змінює значення за замовчуванням, є ламким; інструмент назве це патчем і буде впевнено неправим.
Тому робочий поділ такий: чернетку збирає машина, перед релізом редагує людина. П’ятнадцять хвилин редагування перетворюють правильний список на читабельний: три коміти зливаються в один запис, шість непомітних користувачеві видаляються, а два, сформульовані зсередини коду, переписуються.
Як це виявляється в реальній поставці
Перевірка changelog — чи відкриває його хтось під тиском. Після оновлення о 16:40 щось зламалося; людина, яка ніколи не читала вашого коду, відкриває файл і має менш ніж за хвилину знайти, чи змінювала версія, на яку вона перейшла, те, на що вона зараз дивиться. Усе в конвенції — новіше вгорі, шість фіксованих заголовків, рядок на зміну, наслідки замість правок — існує, щоб зробити цю хвилину можливою.
Де він вироджується
- Згенерований дамп комітів, опублікований без редагування, ніхто не читає двічі.
- Ламкі зміни, випущені як minor чи patch, руйнують контракт версії.
- Немає заявленого публічного API — тоді будь-який рефакторинг начебто ламкий, і ніхто цього не розрізнить.
- Роками сидіти на 0.x зі споживачами в production — це використання нуля, щоб уникнути зобов’язання.
- Повідомлення про депрекацію без версії видалення — за ними ніхто нічого не робить до самого видалення.
- «Виправлення помилок і покращення» як увесь запис — не-відповідь на кожне питання читача.
- Написаний у момент релізу по пам’яті — і саме дрібна ламка зміна виявляється забутою.
Коли це застосовувати
Застосовуйте, коли
- Інші люди чи команди залежать від вашого софту й вирішують, коли оновлюватися.
- Ви публікуєте бібліотеку, API або будь-що версійоване.
- Підтримці треба знати, до якої версії належить повідомлена проблема.
- Користувачі встановлюють оновлення самі, а не отримують їх непомітно.
Уникайте, коли
- Внутрішній сервіс з одним споживачем, що сидить поруч, — повідомлення дешевше.
- Вебзастосунок із безперервним деплоєм, де користувач ніколи не обирає версію.
- Він генерувався б і ніколи не читався — це супровід без читача.
- Реліз-ноти для кінцевих користувачів це вже покривають — не ведіть два документи, що дублюються.
Було корисно?
Поділіться з тим, хто працює над тією ж задачею.