Семантическое версионирование
Что значат цифры в версии 2.4.1: MAJOR.MINOR.PATCH, диапазоны зависимостей и связь с git-тегами.
Зачем версии вообще нужны правила
Версия 2.4.1 — не случайный набор цифр. Когда у тебя десяток
зависимостей, и каждая обновляется по-своему, нужен общий язык: «эта
версия совместима со старой» или «эта сломает API». Договорённость, как
читать эти цифры, называется семантическое версионирование (SemVer).
Без правил 1.0 → 1.1 могло бы означать что угодно: мелкую правку или
полное переписывание. SemVer убирает гадание.
MAJOR.MINOR.PATCH
Версия из трёх чисел, разделённых точками:
2 . 4 . 1
MAJOR MINOR PATCH
- PATCH (
2.4.1→2.4.2) — багфиксы, ничего не сломано, API тот же. Обновляться безопасно. - MINOR (
2.4.1→2.5.0) — новая функциональность, но старое продолжает работать. Обратная совместимость сохранена. - MAJOR (
2.4.1→3.0.0) — несовместимые изменения. Что-то в API убрали или поменяли, старый код может сломаться.
Правило простое: ломаешь совместимость — поднимай MAJOR. Добавляешь, не ломая — MINOR. Чинишь — PATCH.
До релиза версия часто начинается с 0.x. Это значит «API ещё не
стабилизирован, может меняться в любой момент». Предрелизы помечают
суффиксом: 1.0.0-rc.1, 2.0.0-beta.
Диапазоны в зависимостях
SemVer нужен, чтобы менеджеры пакетов умели обновлять зависимости
безопасно. В package.json встречаются такие записи:
"express": "^4.18.2",
"lodash": "~4.17.21"
^(caret) разрешает обновления, не меняющие MAJOR:^4.18.2возьмёт4.19.0,4.18.5, но не5.0.0.~(tilde) разрешает только PATCH:~4.17.21возьмёт4.17.25, но не4.18.0.- точная версия (
4.18.2) фиксирует ровно её.
Логика опирается на SemVer-обещание: внутри одного MAJOR ничего не
ломается, поэтому ^ обновлять относительно безопасно. Если пакет не
держит SemVer честно, это обещание не работает. Отсюда lock-файлы,
которые фиксируют точные версии для воспроизводимости.
Особый случай: версии 0.x
Правило «caret держит MAJOR» перестаёт работать, когда MAJOR равен
нулю. Для нулевых версий SemVer вообще не даёт гарантий: 0.x считается
периодом активной разработки, и ломающее изменение там выпускают в
MINOR.
Менеджеры пакетов это учитывают и ужимают диапазон:
^1.2.3 → >=1.2.3 <2.0.0 обновляется до 1.9.9
^0.2.3 → >=0.2.3 <0.3.0 до 0.3.0 не поднимется
^0.0.3 → >=0.0.3 <0.0.4 то есть только эта версия
Ошибка тут стоит дорого именно потому, что интуиция говорит обратное.
Человек читает ^0.2.3, думает «обновится в пределах нуля, доедет до
0.9», ставит зависимость и ждёт свежих версий. А npm честно держит его
на ветке 0.2.x и не подтягивает даже критичные фиксы, выпущенные в
0.3.1.
Практический вывод: у зависимости на 0.x следи за обновлениями
руками. Автоматика их не привезёт.
Связь с git-тегами
Версию в git фиксируют тегом — именованной меткой на конкретном
коммите. По соглашению тег версии начинается с v:
git tag -a v2.4.1 -m "release 2.4.1"
git push origin v2.4.1
Тег v2.4.1 навсегда указывает на коммит, из которого собран этот релиз.
CI обычно настроен так, что push тега запускает сборку и публикацию
артефакта с этой версией. Так номер версии, коммит и собранный образ
оказываются жёстко связаны.
Что важно запомнить
SemVer читается как MAJOR.MINOR.PATCH: MAJOR ломает совместимость, MINOR добавляет без поломок, PATCH чинит.
^ в зависимостях разрешает обновления внутри одного MAJOR, ~ — только
PATCH. Lock-файлы фиксируют точные версии, когда пакеты держат SemVer
нечестно.
Для нулевых версий caret ведёт себя иначе: ^0.2.3 это
>=0.2.3 <0.3.0, а ^0.0.3 вообще пришпиливает одну версию. Такие
зависимости обновляют руками.
Версию в git закрепляют тегом vX.Y.Z; push тега обычно запускает сборку
релиза в CI.
В следующем уроке разберём теги и релизы в git подробнее, и как из них собираются release-страницы.
Прошли материал до конца? Отметьте урок пройденным.
Прогресс сохранён в этом браузере
Почистишь историю или откроешь с телефона, и отметки пропадут. Оставь почту, они переедут в аккаунт. Пароль придумывать не нужно.
Готово. теперь в аккаунте: прогресс виден с любого устройства. Мой прогресс