Пошук уроків, статей та іншого контенту
Проєктуємо процес релізу з тегами, changelog, release-гілками та відкатом невдалих версій.
Релізний workflow має однозначно відповідати на такі питання:
який коміт потрапив у конкретну версію;
які зміни входять до релізу;
де стабілізується версія перед випуском;
як виправляються критичні помилки після релізу;
як швидко повернути попередню працездатну версію;
як синхронізувати виправлення між релізною та основною гілками.
У Git немає вбудованого «правильного» процесу релізу. Команда проєктує його навколо кількох об’єктів:
стабільної гілки, наприклад main;
тимчасових release-гілок;
тегів версій;
файлу CHANGELOG.md;
правил для виправлень і відкату.
Далі використовується схема з SemVer-версіями на кшталт v2.4.0:
MAJOR — несумісні зміни API або поведінки;
MINOR — нові сумісні можливості;
PATCH — виправлення помилок без зміни сумісного API.
mainГілка main містить інтегрований код, який потенційно можна випустити. Вона не повинна містити незавершених змін або комітів, які навмисно ламають збірку.
Для main зазвичай налаштовують захист:
прямий push заборонений;
зміни потрапляють через Pull Request;
обов’язково проходять автоматичні перевірки;
релізні теги створюють лише уповноважені учасники.
Release-гілка створюється, коли команда вирішує стабілізувати конкретну версію:
release/2.4Вона потрібна, якщо підготовка релізу може тривати довше, ніж один короткий Pull Request. У цей час у main можуть продовжуватися розробка наступних можливостей.
У release-гілку дозволено додавати лише зміни, необхідні для цього релізу:
виправлення помилок;
оновлення версії;
зміни конфігурації, пов’язані з релізом;
уточнення документації та CHANGELOG.md.
Нові функціональні можливості до вже відкритої release-гілки зазвичай не додають.
Hotfix — це термінове виправлення вже випущеної версії. Його можна створити від відповідного релізного тегу або від поточної release-гілки:
hotfix/2.4.1На відміну від звичайної release-гілки, hotfix має мінімальний обсяг і короткий життєвий цикл.
Перед створенням release-гілки потрібно переконатися, що локальний main відповідає віддаленому репозиторію:
git fetch origin --prune
git switch main
git pull --ff-only origin mainПараметр --ff-only забороняє Git автоматично створити merge-коміт, якщо локальна історія розійшлася з віддаленою. Це змушує спочатку явно розібратися з розбіжністю.
Створення release-гілки:
git switch -c release/2.4
git push -u origin release/2.4Після цього всі зміни, необхідні для підготовки версії 2.4.0, проходять через Pull Request у release/2.4.
Важливо зафіксувати склад релізу. Якщо в main продовжують потрапляти нові функціональні зміни, вони не повинні автоматично потрапляти до вже створеної release-гілки.
CHANGELOG.mdCHANGELOG.md має описувати зміни мовою, зрозумілою користувачеві або іншому розробнику. Повідомлення на кшталт fix, update або misc changes не дають достатньо інформації.
Приклад структури:
# Changelog
## [2.4.0] - 2026-09-02
### Added
- Додано імпорт користувачів із CSV-файлів.
### Changed
- Змінено формат відповіді для запиту списку користувачів.
### Fixed
- Виправлено повторне надсилання повідомлень після тимчасової помилки мережі.
### Security
- Обмежено кількість спроб входу для однієї IP-адреси.Для кожної версії бажано розділяти зміни за категоріями:
Added — нові можливості;
Changed — зміни наявної поведінки;
Deprecated — можливості, які ще працюють, але будуть вилучені;
Removed — вилучені можливості;
Fixed — виправлення помилок;
Security — зміни безпеки.
Changelog потрібно редагувати на release-гілці, а не лише після створення тегу. Тоді він проходить звичайний code review і є частиною того самого коміту або набору комітів, який перевіряється перед релізом.
Для перевірки історії між двома тегами можна використати:
git log --oneline --decorate v2.3.1..v2.4.0Для отримання списку авторів і повідомлень комітів:
git log \
--pretty=format:'%h %ad %an — %s' \
--date=short \
v2.3.1..v2.4.0Для перевірки фактичної різниці файлів:
git diff --stat v2.3.1..v2.4.0
git diff v2.3.1..v2.4.0 -- CHANGELOG.mdДіапазон v2.3.1..v2.4.0 означає коміти, доступні з другого тегу, але відсутні в першому. Якщо один із тегів відсутній локально, спочатку потрібно завантажити теги:
git fetch origin --tagsПеред створенням фінального тегу потрібно виконати перевірки, визначені проєктом. Наприклад:
git switch release/2.4
git status
git diff origin/main...HEADgit status має показати чисте робоче дерево. Команда git diff origin/main...HEAD допомагає побачити зміни release-гілки відносно спільної бази з main.
Типовий порядок перевірок:
запустити форматування або перевірку стилю;
виконати статичний аналіз;
запустити модульні та інтеграційні тести;
зібрати артефакт застосунку;
перевірити міграції бази даних;
виконати smoke-тести у середовищі, наближеному до production;
перевірити вміст CHANGELOG.md і номер версії.
Команди залежать від конкретного проєкту. Git відповідає за історію змін, але не визначає, як саме запускаються тести або збірка.
Після завершення підготовки release-гілку зливають у main через Pull Request:
git switch main
git pull --ff-only origin main
git merge --no-ff release/2.4У командах, де зміни потрапляють у захищену гілку, замість локального merge зазвичай створюють Pull Request. Важливо, щоб у main потрапив саме перевірений стан release-гілки.
Тег має вказувати на конкретний коміт, який є джерелом релізу. Для версій краще використовувати анотовані теги:
git switch main
git pull --ff-only origin main
git tag -a v2.4.0 -m "Release v2.4.0"
git show --stat --decorate v2.4.0
git push origin v2.4.0Анотований тег містить:
ім’я тегу;
повідомлення;
автора тегу;
дату;
коміт, на який він вказує.
Тег не публікується автоматично під час звичайного git push. Його потрібно відправити окремо:
git push origin v2.4.0Можна відправити всі локальні теги:
git push origin --tagsАле для контрольованого релізного процесу краще явно вказувати конкретний тег. Це зменшує ризик випадково опублікувати тестові або застарілі теги.
Після публікації перевірте, що тег вказує на очікуваний коміт:
git rev-parse v2.4.0
git rev-parse mainУ цьому сценарії обидві команди мають повернути ідентичний ідентифікатор коміту.
Після публікації тег вважається незмінним. Не потрібно видаляти v2.4.0 і створювати його заново на іншому коміті, якщо виявлено помилку.
Такий підхід небезпечний, тому що:
різні локальні клони можуть мати різні значення одного тегу;
системи CI/CD можуть уже завантажити старий коміт;
артефакти з однаковою версією можуть мати різний вміст;
аудит історії стає ненадійним.
Якщо помилковий реліз уже має тег v2.4.0, потрібно випустити наступну версію, наприклад v2.4.1.
Після успішного релізу release-гілку можна видалити, якщо команда не планує використовувати її для подальших виправлень:
git push origin --delete release/2.4
git branch -d release/2.4Перед видаленням переконайтеся, що:
release-гілка злита в main;
тег створений на потрібному коміті;
тег опублікований у віддаленому репозиторії;
CI/CD успішно створив і розгорнув реліз;
необхідні виправлення не залишилися лише в release-гілці.
Якщо release-гілка є довготривалим джерелом для підтримки production, її можна залишити. Проте в такому разі мають бути чіткі правила, як зміни з неї потрапляють назад у main.
Припустімо, що в release/2.4 знайдено помилку. Виправлення створюють окремою гілкою:
git switch release/2.4
git pull --ff-only origin release/2.4
git switch -c fix/retry-message-deliveryПісля внесення змін:
git add src/ CHANGELOG.md
git commit -m "Fix duplicate message delivery"
git push -u origin fix/retry-message-deliveryДалі створюється Pull Request у release/2.4.
Після merge виправлення має бути перенесене в main. Це можна зробити merge всієї release-гілки або окремого коміту, залежно від політики команди. Головне — не залишити виправлення тільки в релізній гілці.
Якщо release-гілка ще не злита в main:
git switch main
git pull --ff-only origin main
git merge --no-ff release/2.4
git push origin mainЯкщо main вже містить нові зміни, конфлікти потрібно розв’язувати уважно, а після merge повторно запустити повний набір перевірок.
Припустімо, що production працює на v2.4.0, але в цій версії знайдено критичну помилку.
Створіть hotfix від тегу:
git fetch origin --tags
git switch -c hotfix/2.4.1 v2.4.0Це важливо: hotfix починається саме зі стану, який реально був випущений, а не з поточного main, де можуть бути незавершені або ще не випущені зміни.
Після виправлення:
git add src/ CHANGELOG.md
git commit -m "Fix critical authentication error"
git push -u origin hotfix/2.4.1Після перевірок hotfix зливають у main, а потім створюють новий тег:
git switch main
git pull --ff-only origin main
git merge --no-ff hotfix/2.4.1
git push origin main
git tag -a v2.4.1 -m "Release v2.4.1"
git push origin v2.4.1Якщо існує активна release-гілка release/2.4, виправлення потрібно перенести і до неї. Інакше наступний реліз може випадково повернути вже виправлену помилку.
Відкат має два різні значення:
повернути production до попереднього артефакту;
скасувати зміни в Git, щоб помилка не потрапила в майбутні релізи.
Ці дії не завжди виконуються одним і тим самим кроком.
Якщо production підтримує вибір версії, попередню версію можна розгорнути за її тегом:
git fetch origin --tags
git show v2.3.1Далі система розгортання має використати коміт, позначений v2.3.1. Сам Git не виконує deployment, тому конкретна команда залежить від CI/CD та платформи.
Такий відкат повертає запущений код до попереднього стану, але не виправляє main. Після стабілізації потрібно додати коректне виправлення в репозиторій.
git revertЯкщо потрібно скасувати зміни в історії main, використовуйте git revert, а не переписування опублікованої історії:
git switch main
git pull --ff-only origin main
git revert <commit-sha>
git push origin maingit revert створює новий коміт, який скасовує зміни попереднього. Історія залишається доступною для аудиту.
Якщо невдалий реліз складається з одного merge-коміту, може знадобитися:
git revert -m 1 <merge-commit-sha>Параметр -m 1 вказує, яку батьківську лінію вважати основною. Перед таким відкатом обов’язково потрібно перевірити результат у тестовому середовищі, оскільки скасування merge-коміту може зачепити багато файлів.
reset для спільної гілкиКоманда на кшталт:
git reset --hard v2.3.1
git push --force origin mainпереписує історію віддаленої гілки. Це може порушити роботу інших розробників, CI/CD і систем аудиту.
reset доречний для локальної приватної гілки, але не для вже опублікованої спільної гілки. Для спільної історії використовуйте revert або deployment rollback.
Нижче наведено послідовність команд для релізу 2.4.0. Перед виконанням потрібно адаптувати шляхи до файлів і команди перевірок під конкретний проєкт.
# Оновлюємо локальні посилання та переходимо на main
git fetch origin --prune --tags
git switch main
git pull --ff-only origin main
# Створюємо release-гілку
git switch -c release/2.4
git push -u origin release/2.4
# Після редагування CHANGELOG.md та файлу версії
git add CHANGELOG.md package.json
git commit -m "Prepare release v2.4.0"
git push origin release/2.4
# Після code review і проходження перевірок зливаємо release-гілку в main
git switch main
git pull --ff-only origin main
git merge --no-ff release/2.4
git push origin main
# Створюємо незмінний анотований тег на релізному коміті
git tag -a v2.4.0 -m "Release v2.4.0"
# Перед публікацією перевіряємо коміт і опис тегу
git show --stat --decorate v2.4.0
# Публікуємо саме цей тег
git push origin v2.4.0
# Видаляємо тимчасову release-гілку після перевірки релізу
git push origin --delete release/2.4
git branch -d release/2.4У реальному процесі merge у main зазвичай виконується через Pull Request. Команди після merge показують логічний порядок операцій, а не обов’язково спосіб, яким їх виконують вручну.
Зафіксуйте правила релізу в документації репозиторію:
формат тегів: vMAJOR.MINOR.PATCH;
хто має право створювати та публікувати теги;
коли створюється release-гілка;
які зміни дозволені в release-гілці;
де і як оновлюється CHANGELOG.md;
які перевірки є обов’язковими;
як виконується deployment rollback;
як виправлення переносяться назад у main;
чи дозволено видаляти release-гілки;
що робити з уже опублікованим невдалим тегом.
Також корисно перевіряти реліз до публікації:
# Поточна гілка має бути main
test "$(git branch --show-current)" = "main"
# Робоче дерево має бути чистим
test -z "$(git status --porcelain)"
# Тег має вказувати на поточний коміт
test "$(git rev-parse v2.4.0)" = "$(git rev-parse HEAD)"
# У changelog присутня поточна версія
grep -q '^## \[2.4.0\]' CHANGELOG.mdЯкщо будь-яка команда завершується з помилкою, реліз не слід публікувати до з’ясування причини.
Тег версії не можна перевикористовувати для іншого коміту. Помилковий реліз виправляється новою patch-версією.
Тег потрібно створювати після merge перевіреного стану в main. Перед публікацією перевірте:
git rev-parse HEAD
git rev-parse v2.4.0Виправлення, внесене під час стабілізації, потрібно перенести до main. Інакше воно може зникнути під час наступного релізу.
Це збільшує обсяг тестування і робить версію непередбачуваною. Для нової функціональності створюйте окрему гілку або плануйте її для наступного релізу.
git push --forceПримусове переписування main приховує історію проблеми та може пошкодити локальні клони. Для спільних гілок використовуйте git revert.
Гілка рухається вперед, тому її стан може змінитися після початку deployment. Для відтворюваного релізу використовуйте конкретний тег або ідентифікатор коміту.
CHANGELOG.md повинен перевірятися разом із кодом. Якщо опис змін додається після deployment, є ризик пропустити важливу несумісну зміну або виправлення безпеки.
Надійний Git-реліз складається з послідовних кроків:
оновити main і створити release-гілку;
заборонити в ній незаплановані функціональні зміни;
оновити версію та CHANGELOG.md;
виконати повний набір перевірок;
злити перевірений стан у main;
створити анотований тег на точному релізному коміті;
окремо опублікувати тег;
для критичних помилок створити hotfix із попереднього релізу;
синхронізувати hotfix із main і активними release-гілками;
виконувати rollback deployment окремо від скасування змін у Git.
Теги забезпечують відтворюваність версій, release-гілки ізолюють стабілізацію, changelog пояснює зміни, а revert і hotfix дають контрольований шлях відновлення після невдалого релізу.