Теорія
Релізи на GitHub і версії: теги, SemVer, changelog
Що таке тег Git, як читати номер версії на кшталт v1.4.1 (SemVer простими словами), як працюють релізи на GitHub і згенеровані release notes, чим вони відрізняються від changelog, як перевірити, чи є виправлення у версії, і чому «змерджено», «випущено» і «доступно всім» можуть бути трьома різними моментами.
~10 хв читання · 11 вправ · 250 балів
Перед початком
У якій версії виправлення?
Знову в продуктовій команді Котокорму, і підтримка має прохання щодо виправлення кнопки: вони хочуть писати клієнтам «виправлено у версії така-то», як у примітках до оновлень застосунку. Чесна відповідь поки що: #134 не входить у жодну версію.
У цьому уроці ти дізнаєшся, що означають теги й номери версій, як працюють релізи й нотатки до релізів на GitHub і чому злиття, реліз і доступність для кожного користувача можуть бути трьома різними моментами.
Тег: незмінна назва для одного коміту
Тег (tag) це незмінна назва для одного коміту. Гілка рухається вперед із кожним новим комітом, а тег лишається саме там, де його поставили. Тому версії і є тегами: v1.3.0 має означати той самий код і завтра, і за рік.
Створити тег можна двома командами:
git tag -a v1.3.0 -m "Cat treats bundle"
git push origin v1.3.0
-a створює анотований тег із власним автором, датою й повідомленням; звичайний пуш теги не надсилає, тож друга команда відправляє його на GitHub.
У Котокорму v1.3.0 позначає 8be2f70, набір смаколиків для котів. Відтоді main пішла на п'ять комітів уперед, зокрема з виправленням кнопки #134 (d51c7e8). Тож #134 на сайті з моменту свого деплою, але ні в якій версії ще немає: жоден тег не вказує на коміт, який його містить.
8be2f70Add cat treats bundlev1.3.06f2c8a1Raise free-delivery threshold to 1000 UAH (#133)a7d93e4Rewrite delivery page copy (#132)d51c7e8Fix checkout button after cart edits (#134)3b8e1f6Add autumn sale banner (#136)9c4a2d7Add loyalty points behind a flag (#155)main
Граф комітів, від найстарішого: main і її єдиний свіжий тег 1. коміт 8be2f70 у main "Add cat treats bundle", тег v1.3.0 2. коміт 6f2c8a1 у main "Raise free-delivery threshold to 1000 UAH (#133)" 3. коміт a7d93e4 у main "Rewrite delivery page copy (#132)" 4. коміт d51c7e8 у main "Fix checkout button after cart edits (#134)" (виділено) 5. коміт 3b8e1f6 у main "Add autumn sale banner (#136)" 6. коміт 9c4a2d7 у main "Add loyalty points behind a flag (#155)"
Які теги містять коміт, показує git tag --contains d51c7e8; порожня відповідь означає «ще не випущено в жодній версії». Тег схожий на закладку, приколоту до однієї сторінки, поки в кінці зошита з'являються нові.
- Так«#134 на сайті, але ще не в жодній версії:
v1.3.0вказує на раніший коміт».Відділяє «на сайті» від «випущено».
- Не так«
v1.3.0найновіший тег, отже, у ньому все, що є вmain».Тег стоїть на одному коміті й не йде за
main.
Ніколи не переставляй опублікований тег
Технічно тег можна видалити й створити деінде; у git навіть є git tag -f, щоб зробити це примусово. Але щойно тег опубліковано, його ніколи не переставляють.

Люди й інструменти покладаються на те, що v1.3.0 завжди означає той самий код. Підтримка вже сказала клієнтам «виправлено в 1.3.0». Партнер міг на нього зорієнтуватися. Нотатки до релізів, changelog і посилання на порівняння вказують на нього. Переставиш тег, і кожне з цих тверджень тихо змінить зміст. Хто вже отримав старий тег, лишиться зі старою позицією, тож двоє людей дивитимуться на «ту саму» версію й бачитимуть різний код.
Тож коли новій роботі потрібна версія, створи нову версію. Виправлення кнопки з'явилося після v1.3.0? Воно піде в наступний тег, v1.4.0, який міститиме все до власного коміту. Якщо реліз виявився зламаним, випусти виправлення новою PATCH-версією, як-от v1.4.1, а не переписуй стару.
Номери версій дешеві. Довіра до того, що означає номер версії, ні.
- ТакПоставити тег
v1.4.0на найновіший комітmain;v1.3.0лишити на місці.Нова робота, нова версія.
- Не так
git tag -f v1.3.0на сьогоднішнійmain, а тоді пуш ще раз.Кожне «виправлено в 1.3.0» стає неправдою.
Як читати номер версії: SemVer простими словами
Семантичне версіонування (SemVer) записує версію як MAJOR.MINOR.PATCH, і кожне число каже, яка зміна сталася:
- PATCH зростає для виправлень:
1.4.0→1.4.1. - MINOR зростає для нових фіч, що нічого не ламають:
1.4.1→1.5.0. - MAJOR зростає для змін, що ламають щось, на що люди покладаються:
1.5.0→2.0.0.
Коли число зростає, усі праворуч від нього обнуляються. Після 1.3.0 виправлення дає 1.3.1, нова фіча 1.4.0, зміна, що ламає сумісність, 2.0.0.

Формальні правила на semver.org написані для програм, від яких залежать інші програми. Сайт має сам вирішити, що для нього означає «ламає». Правило Котокорму: MAJOR лише тоді, коли перестають працювати старі посилання, збережені кошики чи інтеграції партнерів.
Ще дві домовленості. v у v1.4.0 це просто поширена звичка для назв тегів; сама версія 1.4.0. А суфікс позначає пре-реліз, тестову версію перед справжньою: 1.5.0-beta.1 іде перед 1.5.0.
- ТакПісля
v1.4.0поле для нотатки до подарунка →v1.5.0.Нова фіча: MINOR зростає, PATCH обнуляється.
- Не такПісля
v1.4.0виправлення посилання у футері →v1.5.1.Виправлення підвищує лише PATCH:
v1.4.1.
Порівняння версій: числа, а не абетка
Чи 1.4.10 старша за 1.4.9? За абеткою так, бо «1» іде перед «9». У SemVer ні.
Порівнюй версії частина за частиною, зліва направо, кожну як ціле число: спершу MAJOR, потім MINOR, потім PATCH. Десять більше за дев'ять, тож 1.4.10 новіша за 1.4.9. Будь-яка 1.x старша за 2.0.0, хай які великі в неї інші числа.
Пре-релізи стоять одразу перед версією, до якої ведуть: 1.5.0-beta.1 новіша за будь-яку 1.4.x, але старша за саму 1.5.0. Тож по порядку:
v1.4.1 → v1.4.9 → v1.4.10 → v1.5.0-beta.1 → v1.5.0 → v2.0.0
Не довіряй порядку в списку наосліп. Сторінка тегів GitHub не завжди сортує теги за версіями, а звичайне сортування за абеткою помиляється з 1.4.10. У терміналі git tag --sort=v:refname порівнює числа як числа, хоча щоб суфікси пре-релізів стали перед своїм релізом, потрібне додаткове налаштування. Коли є сумнів, порівняй частини власноруч.
- Так
1.4.9<1.4.10: порівняй 9 і 10 як числа.Кожна частина ціле число.
- Не так«
1.5.0-beta.1новіша за1.5.0, у неї більше символів».Пре-реліз іде перед своїм релізом.
Публікація релізу на GitHub
Реліз на GitHub (GitHub release) це сторінка, побудована на git-тезі: номер версії, нотатки до релізу для людей і файли для завантаження. Тег позначає точний коміт, а реліз пояснює, що змінилося від попереднього. Усі релізи лежать у розділі Releases репозиторію.
Станом на 2026 рік кроки такі: Draft a new release, ввести новий тег, як-от v1.4.0, обрати ціль main (GitHub створить тег під час публікації), вказати попередній тег і натиснути Generate release notes. GitHub перелічить кожен pull request, змерджений від того тегу, з назвою й автором, плюс посилання на порівняння Full Changelog. Добрі назви pull requests тут окупаються вдруге.
Під текстом файли (assets): GitHub завжди додає вихідний код у zip і tar.gz, а команди застосунків прикріплюють зібрану програму. Далі дві позначки: Set as a pre-release для тестових версій і Set as the latest release, що дає найновішому повному релізу бейдж Latest. У терміналі: gh release create v1.4.0 --target main --generate-notes.
v1.4.0
Latest · на 9c4a2d7 · нотатки від Daniel і Sofia
v1.3.0
на 8be2f70 · без сторінки релізу, лише тег
У Котокорму публікація релізу нічого не викладає: кожна зміна вже була на сайті з моменту мерджу. Реліз називає й описує те, що там уже є.
- Так
gh release create v1.4.0 --target main --generate-notesТег, ціль і згенеровані нотатки за раз.
- Не так«Реліз опубліковано, отже, банер нарешті на сайті».
У Котокорму деплой стався під час мерджу.
Нотатки до релізу для людей і changelog
Changelog це запис того, що змінилося в кожній версії, написаний для людей, які нею користуються. Добрі нотатки до релізу це такий запис для однієї версії. Список, який генерує GitHub, це сировина, а не готовий текст: підтримка не зрозуміє «Add loyalty points behind a flag» і не має розповідати клієнтам про роботу, яка ще прихована.
Що згенерувала кнопка Generate release notes · є вище
Тож нагорі дай коротку частину «Для клієнтів і підтримки» простими словами:
- що помітять клієнти (безкоштовна доставка тепер від 1000 грн);
- що виправлено (кнопка оформлення більше не лишається сірою);
- нічого про приховану роботу за вимкненим флагом.

Згенерований список лиши нижче, для інженерів.
Деякі команди ведуть файл CHANGELOG.md із розділами Added, Changed і Fixed; інші використовують сторінки релізів як changelog. Невеликий файл налаштувань .github/release.yml може змусити генератор групувати pull requests за мітками, щоб усе з міткою bug потрапляло в «Fixes».
Читай кожен рядок з одним питанням: чи може підтримка переслати це клієнту як є?
- Так«Виправлено: кнопка оформлення більше не лишається сірою після змін у кошику».
Прості слова, які підтримка може переслати.
- Не так«* Add loyalty points behind a flag by @catchow-daniel in #155»
Мова інженерів, ще й видає приховану роботу.
Змерджено, випущено, видно: три різні моменти
За питанням «це вже на сайті?» ховаються три окремі питання:
- Змерджено: чи зміна в
main(абоdevelop)? - Випущено: чи вона в іменованій версії, тезі з нотатками до релізу?
- Видно: чи можуть клієнти нею справді користуватися?

Наскільки вони рознесені в часі, залежить від команди. У Котокорму змерджено означає «на сайті за кілька хвилин», а реліз з'являється пізніше як іменований знімок: #134 був на сайті з минулої середи, а частиною v1.4.0 став у четвер. Флаги навіть тут відділяють випущене від видимого: #155 є у v1.4.0, але жоден клієнт його не бачить, поки loyalty-points вимкнено.
У команді застосунку з git flow усі три далеко одне від одного. Фіча, змерджена в develop, чекає на релізну гілку, потім на реліз і перевірку в магазинах. Навіть після схвалення магазини можуть розгортати версію поступово на дедалі більшу частку користувачів, тож «випущено» може означати «поки лише в частини». І ніхто нічого не побачить, доки не оновиться.
Тож перш ніж відповісти «чи вже на сайті?», визнач, про який із трьох моментів питають, і відповідай саме на нього.
- Так«#155 змерджено й випущено у
v1.4.0, але приховано: флаг вимкнено».Усі три моменти названо.
- Не так«Це у
v1.4.0, отже, кожен клієнт може цим користуватися».Флаг чи поступове розгортання все ще можуть це ховати.
Порівняння тегів і версія хотфіксу
Коли в п'ятницю посилання меню лояльності стало видимим, виправлення пройшло GitHub flow: малий pull request у main, рев'ю, перевірка на preview, squash-мердж як e5f81a3 і деплой. У GitHub flow хотфікс не окремий тип гілки, а просто малий pull request поза чергою. Від v1.4.0 нічого іншого не зливали, тож це став PATCH-реліз: v1.4.1. Якби туди проскочила нова фіча, чесним номером був би v1.5.0.
Щоб побачити, що саме одна версія додала порівняно з іншою, відкрий порівняння (compare view): v1.4.0...v1.4.1 на GitHub або git log --oneline v1.4.0..v1.4.1 у терміналі. Воно показує коміти, досяжні з другого тегу, але не з першого. Тут це один коміт, e5f81a3 (#158).
Саме тому нотатки до релізу перелічують лише нове від попередньої версії. #134 немає в нотатках v1.4.1, але він є у v1.4.1: він уже був у v1.4.0, а v1.4.1 стоїть далі на тій самій лінії, тож містить усе, що й v1.4.0.
- Так
git log --oneline v1.4.0..v1.4.1→ один коміт, #158Саме те, що додала нова версія.
- Не так«#134 немає в нотатках
v1.4.1, отже, уv1.4.1його немає».Нотатки перелічують нове, а не все, що всередині.
Чи є виправлення в цій версії? Як перевірити
На питання «чи є #134 у v1.4.1?» є надійна відповідь і три способи її отримати:
- Сторінка коміту. Відкрий коміт #134,
d51c7e8. Станом на 2026 рік GitHub показує теги, що його містять:v1.4.0іv1.4.1, але неv1.3.0. У терміналі той самий список друкуєgit tag --contains d51c7e8. - Історія. Подивися історію
mainдо коміту з тегомv1.4.1; якщоd51c7e8на цій лінії, версія його містить. - Сторінки релізів по порядку. Знайди першу версію, у нотатках якої згадано виправлення, і перевір, що жоден пізніший реліз його не відкочує. Перша поява плюс жодного відкату відтоді: виправлення там.
8be2f70Add cat treats bundlev1.3.06f2c8a1Raise free-delivery threshold to 1000 UAH (#133)a7d93e4Rewrite delivery page copy (#132)d51c7e8Fix checkout button after cart edits (#134)3b8e1f6Add autumn sale banner (#136)9c4a2d7Add loyalty points behind a flag (#155)v1.4.00d7b3c9Check flag before showing menu linkfix/loyalty-menu-linke5f81a3Hide loyalty menu link when flag is off (#158)mainv1.4.1
Граф комітів, від найстарішого: main із двома новими тегами 1. коміт 8be2f70 у main "Add cat treats bundle", тег v1.3.0 2. коміт 6f2c8a1 у main "Raise free-delivery threshold to 1000 UAH (#133)" 3. коміт a7d93e4 у main "Rewrite delivery page copy (#132)" 4. коміт d51c7e8 у main "Fix checkout button after cart edits (#134)" (виділено) 5. коміт 3b8e1f6 у main "Add autumn sale banner (#136)" 6. коміт 9c4a2d7 у main "Add loyalty points behind a flag (#155)", тег v1.4.0 7. гілка fix/loyalty-menu-link починається від коміту 9c4a2d7 8. коміт 0d7b3c9 у fix/loyalty-menu-link "Check flag before showing menu link" 9. коміт e5f81a3: fix/loyalty-menu-link змерджено в main через squash "Hide loyalty menu link when flag is off (#158)", тег v1.4.1
Дві перевірки здаються зручними, але на питання не відповідають. Самі нотатки v1.4.1 перелічують лише нове від v1.4.0. А бейдж Merged каже лише, що зміна в main, але не в якій версії.
Відповідь, яку підтримка може переслати: «виправлено в 1.4.0 і в кожній версії відтоді», якщо нічого не відкочено. Це «якщо» важливе: пізніша версія може забрати зміну назад.
- Так
git tag --contains d51c7e8→v1.4.0,v1.4.1Пряма й надійна відповідь.
- Не такПошукати #134 у нотатках
v1.4.1і відповісти «ні».Нотатки перелічують лише нове в цій версії.
Готові потренуватися?
Виконайте вправи уроку й отримайте 250 балів, коли пройдете його вперше.
Розпочати вправи