Коли одночасно підтримується кілька версій продукту (бібліотека з версіями 2.x і 3.x, застосунок, що встановлюється у клієнтів), кожна версія має релізну гілку:
main ── розробка наступної версії
release/3.x ── виправлення для 3.x, теги v3.4.1, v3.4.2
release/2.x ── лише критичні й безпекові виправлення
Два напрямки перенесення виправлень:
1. «Зверху вниз» (backport) - виправлення спершу в main:
git switch release/3.x
git cherry-pick -x a1b2c3d
mainгарантовано містить усі виправлення - регресія в наступній версії неможлива;-xзалишає в повідомленні посилання на оригінальний коміт;- конфлікти, якщо код у старій версії відрізняється.
2. «Знизу вгору» (merge-up) - виправлення в найстаршій підтримуваній гілці:
git switch release/2.x # виправлення тут
git switch release/3.x && git merge release/2.x
git switch main && git merge release/3.x
Так працює, наприклад, Laravel: виправлення потрапляють у гілку найстаршої підтримуваної версії, а потім зливаються вгору. Переваги - кожне виправлення має один коміт, і Git знає, що воно вже є у всіх новіших гілках. Недолік - злиття вгору тягне й те, що для новішої версії не потрібне, і його доводиться скасовувати при злитті.
Як зробити процес надійним:
- автоматизація backport: мітка
backport 3.xна pull request запускає бота (наприклад, GitHub Action), що робить cherry-pick і відкриває новий pull request - людина лише перевіряє; - тести в кожній релізній гілці - CI запускається на всіх підтримуваних гілках, а не лише на
main; - політика підтримки: скільки версій і як довго отримують виправлення (баги - остання версія, безпека - дві), записана й опублікована;
- захист релізних гілок - лише через pull request з рев'ю;
- changelog для кожної гілки - користувачі старої версії мають бачити, що виправлено саме в ній.
Чим менше підтримуваних версій, тим дешевше. Для веб-застосунку, що деплоїться з main, релізні гілки зазвичай зайві: виправлення йде в main і на продакшен звичайним деплоєм, а відкат - повторним деплоєм попередньої версії.