Что такое stable updates
Это направления работы над Debian .
stable (стабильный) дистрибутив — официально выпущенный дистрибутив, в него обычно изменения не вносятся. Найденные ошибки размещаются в отдельном депозитарии, и периодически вносятся в сам дистрибутив, формируя новый выпуск. Принципиальная идея стабильного дистрибутива — все его установки похожи друг на друга. Именно этот дистрибутив можно обычно найти на CD и DVD. На данный момент стабильным дистрибутивом является Debian GNU/Linux 3.0r0, кодовое имя Woody .
Раньше была ротация кодовых имен: например, Woody сперва был unstable , затем testing и теперь stable . Теперь эта ротация имеет место только в стабильном и тестируемом дистрибутивах. Принято решение нестабильный дистрибутив всегда называть Sid.
Debian поддерживает предыдущий и текущий стабильный дистрибутивы. Более старые дистрибутивы попадают в архив. Над ними не осуществляется работа по исправлению ошибок.
Это часть архива Debian , не входящая в официальный дистрибутив. В experimental находятся кандидаты на вхождение в Sid , которые не проходят по критериям качества или имеют серьезные конфликты зависимостей с другими пакетами.
Debian это проект по созданию дистрибутива GNU/Linux, состоящего из свободного программного обеспечения. Требования к лицензии, по которым тот или иной продукт может считаться свободным, описаны в документе Debian Free Software Guides ( DFSG ).
Программное обеспечение, которое не является свободным, не может входить в официальную поставку Debian , и не является частью дистрибутива.
Тем не менее, проект Debian с целью избежания конфликта интересов с пользователями (которые не всегда ценят свою свободу), предоставляет свои ресурсы: файл-серверы, зеркала, система отслеживания ошибок, списки рассылки некоторым пакетам с несвободным ПО. Данные пакеты размещаются в части дистрибутива, имеющей название non-free . При сборке дистрибутива на CD принято non-free выделять в отдельный диск или не включать в дистрибутив вовсе.
Также существет свободное программное обеспечение, которое требует для своей работы несвободные библиотеки или программы. Это программное обеспечение считается частью дистрибутива, и размещается в разделе contrib .
Раньше архив дистрибутива представлял из себя дерево каталогов, где пакеты были отсортированы по назначанию. Затем было принято решение для нестабильного и тестируемого дистрибутива использовать структуру типа pool/main/буква или libбуква/пакет.deb . Эта система оказалась очень удобной и гибкой. Поэтому теперь Debian будет иметь структуру этого класса для всех дистрибутивов.
Существуют два способа указания пути к архиву пакетов Debian .
В случае если вам нужно указать путь к архиву пакетов Debian , построенному в виде стандартной структуры (например, официальное зеркало), надо в файл /etc/apt/sources.list добавить строку вида:
deb protocol://host branch sections
deb-src protocol://host branch sections
- protocol — протокол (file, http, ftp)
- host/path — hostname зеркала и путь до иерархии Debian
- branch — ветка (stable, testing, unstable)
- sections — список разделов дистрибутива разделенный пробелами (обычно main contrib non-free )
deb http://debian.psu.ru stable main contrib non-free
deb-src http://debian.psu.ru stable main contrib non-free
Если же вам нужно указать путь к каталогу с пакетами (например программа, не являющаяся частью Debian ), то следует внести в файл /etc/apt/sources.list следующие строки:
deb protocol://host/path path-to-archive/ deb-src protocol://host/path path-to-archive/
- protocol — протокол (file, http, ftp)
- host/path — hostname зеркала и путь до иерархии Debian
- path-to-archive — путь к каталогу с файлом Packages.gz, обратите внимание на то, что « / » обязателен
Строка deb-src не обязательна, и нужна только в случае, если вы собираетесь самостоятельно перекомпилировать какой либо пакет.
Более подробную информацию вы можете найти в документации на apt и в списках рассылки Debian , посвященных созданию «вспомогательных» депозитариев Debian .
Вы наверное забыли после этого выполнить команду apt-get update . Если эта команда выдает сообщения об ошибках, читайте документацию на apt(8) , и проверяйте.
Если компакт диск создан стандартными средствами и имеет стандартную структуру каталогов Debian (например, любой из дисков созданных debian-cd или jigdo ), достаточно ввести команду
и «познакомить» apt с новым диском.
Можно скачать ISO9660 образы дисков на любом из зеркал, которое вы найдете на сайте Debian, но готовы ли вы к тому, что после скачивания образа в 650 мегабайт, его md5 сумма будет неправильной? 🙂
Существуют два более приятных способа заполучить образы дисков Debian :
- купить копию официальных дисков
- воспользоваться программой jigdo
Если же вы решили скачать образы Debian , настоятельно рекомендую воспользоваться программой jigdo . Она есть как под практически любой * NIX , так и под Windows . Ее принцип работы заключается в том, что вы должны скачать «заготовку» диска в
50 мегабайт, и указать зеркало с которого скачать файлы дистрибутива. jigdo самостоятельно скачает файлы, сложит их определенном месте для дальнейшего использования, а затем соберет из них диск идентичный тому, с которого делалась заготовка, что и подтвердит затем, проверив md5 сумму.
Используя jigdo и имея поблизости хорошее зеркало Debian вы сможете иметь всегда диски со свежим testing или диски с той или иной альтернативной комплектацией.
Если вы правильно указали источники пакетов в /etc/sources.list и выполнили команду apt-get update , достаточно выполнить команду apt-get dist-upgrade .
apt-get install имя_пакета
При установке пакета всегда проверяются зависимости, и если становка пакета требует установки или удаления других пакетов, вам будет предложено ознакомиться с возможными последствиями.
В случае, если вы имеете просто файл пакета, и уверены, что все зависимости удовлетворены, можно установить пакет командой
dpkg -i имя_пакета.deb
apt-get remove имя_пакета
если вы хотите оставить файлы настроек, или
apt-get remove -purge имя_пакета
если вы хотите удалить пакет так, будто он у вас и не был установлен.
При удалении пакета всегда проверяются зависимости, и если удаление пакета требует установки или удаления других пакетов, вам будет предложено ознакомиться с возможными последствиями. Пример:
Я рассмотрю здесь простой способ, основанный на ручной сборке пакета, без использования специфических утилит типа deb-make и других.
Для начала, вы должны иметь, то что вам нужно установить с помощью собираемого вами пакета. Путь это будет какая-либо утилита, расширяющие возможности системы. (С тем же успехом — это могут быть дополнительные файлы шрифтов или еще что-нибудь). Пусть эта утилита называется probe . Положим, что к этой утилите вы написали страничку руководства man с названием probe.1 и кроме того положим, что есть какой-либо файл, где разобран пример работы с данной утилитой с именем example . Путь файл с примером и страничка руководства называются сопровождающими файлами.
Важно, чтобы вы представляли, где должна быть размещена эта утилита и сопровождающие ее файлы. Обычно исполняемые файлы размещают в /usr/bin . Странички руководства man размещают в /usr/man/man.1 , а всякие примеры в /usr/lib/имя_утилиты . Пусть так будет и в нашем случае.
Итак, выполняем следующие шаги:
- Создаем временный каталог с именем DEB
- Создаем в этом каталоге подкаталоги, в которые нужно поместить утилиту и сопровождающие файлы
Создаем в этом каталоге подкаталоги, в которые нужно поместить утилиту и сопровождающие файлы. При этом каталоги создаются так, как будто DEB является корневым каталогом. Таким образом, в нашем случае, файлы должны быть размещены следующим образом:
Вот для чего они нужны:
| control | Служебная |
|---|---|
| conffiles | Список конфигурационных файлов |
| preinst | Скрипт, выполняемый перед началом установки пакета |
| postinst | Скрипт, выполняемый после установки пакета |
| prerm | Скрипт, выполняемый перед удалением пакета |
| postrm | Скрипт, выполняемый после удаления пакета |
Нелишним будет напомнить, что скрипты должны иметь права на выполнение, иначе ничего выполняется у вас не будет.
Я рассмотрю здесь простой способ, основанный на ручной сборке пакета, без использования специфических утилит типа deb-make и других.
Эту информацию впоследствии будет использовать менеджер пакетов dpkg и программа dselect . Информацию можно занести в любом текстовом редакторе. Для нашего случая я привожу уже готовый файл:
Обратите внимание : перед фразой This is my utility пробел. Он указывает, что данная фраза является продолжением описания.
Если его не поставить, то при сборке пакета вы получите сообщение об ошибке.
- Создайте и заполните остальные файлы, указанные в таблице, если ВАШЕМУ пакету это нужно (в данном случае они не нужны).
- Для генерации .deb пакета наберите команду
dpkg -b имя_каталога имя_пакета.deb
В нашем случае эта команда будет выглядеть так:
dpkg -b DEB probe-1.0.deb
Если вы правильно выполнили все описанные выше инструкции, то вы получите файл probe-1.0.deb , который вы можете теперь установить через команду
dpkg -i probe-1.0.deb .
Если эта программа не входит в Debian , обратитесь к списку рассылки и сайту ее разработчиков.
Если же программу еще никто не собрал (или не разместил в собранном виде в Internet), попробуйте сами! Если у вас получится — разместите готовые пакеты, исходные тексты и патчи в виде депозитария Debian , и сообщите с соответствующий список рассылки об этом.
В случае, если программа является не входит в Debian , ее лицензия не противоречит DFSG , и у вас есть желание, возможность и время поддерживать ее для всех платформ, поддерживаемых Debian , попробуйте стать 2 Debian Developer — войдите в сообщество разработчиков Debian !
следующий: 6 Система X Window выше: Русский Debian 3.0 FAQ предыдущий: 4 Настройка приложений   Оглавление Igor A. Tetuev 2002-11-02
Что такое ‘stable’?
У нас на работе как-то был довольно жаркий спор о том, считать ли python 2.7 стабильным. Итоги спора и сам вопрос я оставляю в стороне, а тут я хочу изложить и систематизировать определённые мысли о реальных программах, которые сильно противоречат миру Фон Неймана и Тьюринга.
Мир, в котором работают программисты — это мир правильного кода. Разумеется, в нём есть бесчисленные ошибки, но эти ошибки подлежат исправлению. Если это ошибки в чужом коде, который не исправить, они подлежат документированию и учитыванию в своём коде. Но ошибка — это всегда повод её найти и устранить.
Мир же системного администрирования другой. Тут код, который «какой есть, такой есть». Невозможно даже мельком прочитать исходные тексты всех пакетов даже для самой маленькой и скромной установки. 300+ Мб линукса, исходные коды основных библиотек и программ… Оно в принципе необозримо. Можно знать конкретные программы, конкретные места программ — но невозможно знать весь runtime, всё программное окружение, из которого состоит ОС.
И оно полно ошибок. Можно сколько угодно рассуждать про прелести мат. доказательств кода, но это совершенно не поможет, если сбой обнаружится в проприентарном драйвере видеокарты (казалось бы, и при чём тут сервер?) или сетевой карты с TCP offload.
К проблеме ПО есть совсем другой подход — подход сугубо практический. У нас есть априори багованный код, который иногда работает как мы ожидаем этого.
И вот вокруг этого «иногда» и строится вся концепция «стабильности» и product-ready.
Мы признаём, что программа полна ошибок, и что ошибки могут вызываться ошибками в других программах, сочетанием ошибок и их отсутствием. Иногда мы даже знаем, что две ошибки в разных программах могут взаимно нейтрализовываться.
Мы принимаем это «как есть» и стремимся к такой ситуации, в которой ошибок с большой вероятностью нет. Где ошибок меньше всего? Правильно, там, где тестировали больше всего. Если известно, что foobar 1 2 даёт правильный результат, то вероятнее всего там ошибок нет. Что, кстати, вовсе не означает, что foobar 2 1 отработает правильно. Не говоря уже про foobar -1 -2, foobar 1.2 2, \\windows\path\foobar 1 2, foobar «01» «02» и т.д.
Другими словами, мы начинаем говорить о категории «тестированности ПО». Очевидно, что все варианты со всеми данными протестированы быть не могут — но чем больше определённые ветви кода тестируются, тем выше вероятность, что там мало ошибок.
Итак, чем больше тестирования, тем лучше.
Наибольшее тестирование программы проходят в настройках по-умолчанию и типовых конфигурациях из best practicie. Если нет оснований делать своё — нужно делать типичное.
То же касается и выбора ПО. Если нет принципиальной разницы — нужно использовать то, что предлагается по-умолчанию в дистрибутиве. Не то, чтобы оно было лучше — его просто больше использовали.
Не буду голословным, расскажу маленькую поучительную историю из жизни Селектела: Довольно долго мы использовали python 2.4 (по-умолчанию в centos 5.5). Программисты много канючили и хотели python 2.6, потом грязными хаками (использованием библиотек, которые работают только с 2.6+) практически предъявили ультиматум. После первичного тестирования, было принято решение о принятии 2.6 в рабочую среду.
Большинство наших сервисов реализовано по принципу easy fall — как только программе что-то не нравится, она тут же (контролируемо) завершается и перезапускается внешним сервисом перезапуска. Это решает проблему очень обширной логики обработки временных ошибок (недоступности базы данных, нехватки места и т.д.) и смены управляющих (смена мастера в кластере, в пуле, смена адреса в файле конфигурации т.д.). Одна из программ зависела от мастера пула (который один в пуле) и на остальных серверах пула (слейвах), обнаружив, что мастера нет, спокойно завершалась, перезапускалась (с задержкой) и снова завершалась. Если мастер менялся, то программа на старом мастере завершалась и переходила в режим ожидания, а на новом с небольшой задержкой начинала работать.
На Python 2.4 оно работало замечательно. Пришёл python 2.6… И мы обнаружили значительное потребление процессрного времени простаивающей системой. Виновником оказался именно python2.6 — он стартовал (вместе с новыми библиотеками) существенно дольше, чем python 2.4.
С точки зрения программиста: что за хрень?
С точки зрения системного администратора: обновили ПО на новую версию — огребли неожиданных проблем.
… Кстати, проблему решили специальным условием в программе — по отсутствию мастера она не завершается, а спит и пробует снова, то есть нам пришлось даже поменять архитектуру приложения, частично отказавшись от принципа easy fall.
Казалось бы мелочь, фактических ошибок в коде нет — а последствия есть, и не особо приятные.
Таким образом возникает естественная потребность в консервативности (как было, пускай так и будет) — откуда и появляются «тухлые» дистрибутивы с древним софтом и десятилетними сроками поддержки этого самого софта. Главная причина — боязнь изменений в рабочей среде.
Большинство дистрибутивов линукса можно квалифицировать по степени приверженности к stable. Ключевым принзнаком является то, как обновляется софт — только ли обновления безопасности, или же допустимым является обновление ПО на новые версии без смены версии всего дистрибутива.
Это является водоразделом между разными дистрибутивами Linux: Например, ubuntu позволяет себе менять версии ПО; Debian — нет. Таким образом, Debian более консервативный, и уже только по этому более подходящий к серверному применению. Наиболее консервативным является Red Hat, у которой RHEL 4.2 всё ещё поддерживается. Я не помню точно, но кажется, поддержку систем на linux 2.4 они то ли ещё не закончили, то ли закончили в ближайшее время.
И более того, я могу предположить, что в обозримое будущее RH или кто-то ещё, нацеленный на энтерпрайз рынок выпустит продукт с ещё большим циклом поддержки (лет 15-20). Ради чего? Ради того, чтобы «один раз поставить» и больше об этом не думать.
Кстати, Microsoft, включающая в critical обновления серверной ОС новые версии браузера делает явную глупость, нарушая идеологию стабильности.
Нужны ли security updates?
Вы знаете, я видел интересную позицию, что в некоторых конфигурациях — нет. Мол, если оно так работает, больше её ни при каких условиях трогать нельзя. И более того, известно несколько случаев из практики, когда security updates ломали функционал ПО.
Однако, общая практика говорит, что обновления с исправлениями ошибок должны устанавливаться. Ключевым отличием обновления с багфиксами от новых версий ПО является отсутствие новой функциональности. Исправляются только ошибки, в остальном (стремсятся к тому, чтобы сохранить) функциональность на том же уровне.
Bleeding Edge
Обратной к стабильности является концепция «bleeding edge». Самая свежая версия. Иногда даже из nightly builds (то есть даже не версия, а промежуточное состояние ПО в ходе разработки). Плюсы у Bleeding Edge на самом деле есть.
Во-первых, вы используете нетипичную версию. То есть с большой вероятностью, её баги ещё никому не известны и под них нет эксплоитов. Во-вторых, багфиксы для вас выходят в первейшую очередь. В третьих новый функционал доступен «из-под пера».
Но цена этого велика — никто не тестировал это ПО (и вы в первых рядах тех падших воинов, из которых складывается стена stable), все его баги, несовместимости, глупости и опечатки — ваши.
Выбор — за вами. Я, например, вполне использую сместь sid и experimental Debian дома (то есть почти тот самый Bleeding Edge), «stable» (относительно) LTS Ubuntu на ноутбуке на работе и stable (без кавычек) Debian/Centos на серверах. Более того, между выходом нового дистрибьютива и моментом обновления на него я предпочитаю выждать несколько месяцев (иногда — вплоть до окончания поддержки старого) — за это время в новом дистрибьютиве исправляют несколько ошибок, решают потенциальные проблемы совместимости и т.д. По-хорошему это должны были делать до момента объявления релизом — но лучше перебдеть, чем поиметь бессонную ночь с разгребанием проблем.
Что такое stable updates


1.6. Жизненный цикл выпуска
СЛОВАРЬ Релиз
1.6.1. Экспериментальный Статус
1.6.2. Нестабильный Статус

Рисунок 1.2. Компиляция пакета с помощью узлов автоматической сборки
БЕГЛЫЙ ВЗГЛЯД buildd , рекомпилятор пакетов Debian
1.6.3. Миграция в Testing
ЗАМЕТКА Ограничения Testing
СООБЩЕСТВО Менеджер релиза
1.6.4. Переход из тестируемого выпуска в стабильный выпуск

Рисунок 1.3. Путь пакета через различные версии Debian
СЛОВАРЬ Заморозка: финишная прямая
CULTURE GNOME and KDE Plasma, graphical desktop environments

Рисунок 1.4. Хронологический путь программы упакованной Debian
1.6.5. Oldstable и статус Oldoldstable
СООБЩЕСТВО Компании спонсирующие долгосрочную поддержку (LTS)
Что такое stable updates
A while ago, i wrote an article called «Never update anything» that brought to light some of the issues with our current approaches to versioning software and the shortcomings of semantic versioning in particular. However, while i did offer some suggestions for creating more stable software at a slower pace, it feels to me that it’d require its own versioning system.
This article is an attempt at describing one such system, which i will probably end up using it for my own SaaS business in the coming years and i urge others to have at least a brief look at some of the ideas presented in this article.
Why we need a new versioning system
The pace at which we move along is too fast, with new features in our software being released every month, if not every week. At the same time, however, the majority of the software costs still lie in the maintenance process (PDF link). We do expect to write our software once and to have it work for as long as necessary in lieu of bug fixes or us needing to add new features ourselves, as opposed to this metaphorical rug of stability being pulled out from under our feet by a seemingly innocent update at some point in time. In this context, added features and changes to the state of our libraries, dependencies or software packages all imply it being more akin to a spreading infection, rather than useful additions to our toolbox.
At the same time, as stated in that other article of mine, we can’t not update our software either — due to some very unfortunate realities of our world, we’ll still need very particular otherwise non-breaking bug fixes or at the very least to get regular security updates as necessary. And yet, you try convincing anyone, for example, the developers of MySQL or MariaDB, to have branches of their codebases and versions that do nothing apart from fixing bugs in perpetuity — in most cases, new features (and thus risks) will still be snuck in, because branching the whole codebase and then backporting fixes will only lead to utter chaos due to simple mathematics. If you have 5 feature releases per year and you want to support each release for 5 years, then after 5 years you’ll need 25 separate versions of your codebase. No one can deal with that level of branching.
Many of the larger corporations out there just sidestep this issue entirely, by just dropping software for releases that are older than X years. This, coupled with minor releases being the only way to get updates which shouldn’t break compatibility, but in practices sometimes do anyways, leads to us never being able to rely upon our dependencies, without having extensive test suites in place and us not being ready to keep up with the release notes and these release cycles. And, as my experience shows, this only ever leads to working with deprecated and insecure packages, even in governmental systems. That’s unacceptable, we need to do better, or at least move in the direction of doing better.
What’s wrong with our current approaches
Furthermore, the major versions and the feature versions don’t actually mean anything. For example, if we take a piece of software with the version of 5.7.36 and another version of 8.0.27, what does that actually tell us? Do we have any idea of what’s in these versions or even what we’re currently looking at? It doesn’t and i’d posit that that’s also a problem. Once you have a project that has a pom.xml with about 100 to 200 external libraries as dependencies, you’ll understand my suffering — to figure out what needs updating and how old each of those packages are, you can’t just look at the version numbers which in this case are just nonsensical strings of text, but have to open the release history for each of them (or find out a way to automate it, which can be either painful or impossible, depending on how much time/knowledge you have).
Luckily, some of the software packages out there have actually been surprisingly sane in this regard and format their versions in a way that immediately gives you a better idea of what you’re looking at. For example, let’s look at my install of IntelliJ IDEA, a lovely Java IDE by JetBrains:

While the latter versions are similarly meaningless to the example above, the inclusion of the release year gives you immediate feedback about how old the particular piece of software is. Seeing 2015. there would without a doubt make you more concerned than seeing 2020. would and rightfully so! That’s a simple, yet a very clear example of why having the versioning system encode information like that would be useful. But let’s look at some more software, for example, releases of Ubuntu:

Not only do we have the release year given, but we also see that we’re dealing with a long term support (LTS) version, which should be more stable than the latest ones by definition! While the latter numbers within the version still are pretty useless to an outsider, because frankly you can’t encode everything that has changed into a short string without having a full changelog somewhere, knowing which «edition» of the software we’re dealing with is still nice!
Similarly, the Unity game engine also adopts an approach that’s very much like what Ubuntu does:

In my eyes, that sort of versioning is very close to what should be used in any and all pieces of software, at least until something better comes along. Yet, it seems like these approaches haven’t really seen more widespread success, or at least no one tries talking about them that much. So, let’s shamelessly steal some of these good practices that have vaguely shown up over the years in many of the projects out there, and let’s give them a formalized name and a list of instructions to describe them.
Introducing the Stable Software Release System
In the spirit of the SemVer site, let’s give some formal guidelines:
Each release must use the following format: YEAR-TYPE-NUMBER
Where:
YEAR — is the current year, for example, 2021
TYPE — is the release type, depending on project specifics; suggested values are «stable» (the equivalent of LTS) and «latest» (for development releases and rolling releases)
NUMBER — is an unsigned integer, starting at 0 and is incremented with each next release for that particular YEAR & TYPE combination

Because of the format above, you may have «large» releases which bundle breaking changes of any kind at most once per year.
Everything else depends on the TYPE value. Following the recommended naming above:
stable — will only contain non-breaking backwards compatible changes: bug fixes and security updates
latest — will contain feature releases of any sort, which add new functionality to the codebase

Because of the grouping above, for each «large» (yearly) release you’ll have a split of your codebase into no more than 2 branches, one which will introduce new functionality and another that will only have backported fixes.
These should be developed in parallel, also addressing the slowly diverging codebases and providing each version with fixes for their unique contents.
At the end of a year, the current «latest» release can become the next «large» (yearly) release, while also splitting off into a new «stable» release at that point in time.
Thus, updating between versions may be done in the following manner:
stable — the people using any stable release may continue to do so throughout its lifecycle (depending on the project, whether it’s supported for 1 year or 5 years)
latest — the people using any latest release may continue to use the new features, until eventually either migrating over to the next «latest» release, or choosing to stick with the next «stable» release

The long term implications
That’s about it! Now, personally, i’d say that the above method is better than semantic versioning and most others due to a variety of reasons:
- it’s extremely simple to implement
- it gives you immediate information about how old any system or dependency is
- every «latest» version eventually becomes a «stable one», so that you can switch over to that if you only need a particular new feature in one point in time but want to settle down later
- alternatively, you can treat the consequent «latest» versions as rolling release, since it’s one uninterrupted codebase, if you can keep up with the changelogs, you can always run the latest software
- older «stable» versions can eventually not worry about parity with the latest ones for backporting, since eventually they won’t have a corresponding «latest» version to match and will be standalone; these are the JDK 8 and MySQL 5.7 of the world, on which much of the world runs on
- better yet, knowing that there’s bound to be an EOL for a particular «stable» version, a migration guide should be easy to create; for example, if you choose to support your LTS releases for 5 years, you’ll know that you’ll need at least 1 guide for the 2020-stable-NUMBER version to something newer, one for 2021-stable-NUMBER to something newer and so on
- best of all, the TYPE part of the version can correspond to Git branches 1:1, further simplifying anything, since most projects out there already have a development and maintenance branch of some sort
- it should satisfy everyone within your community, both those that want stable software that doesn’t break, as well as those who want all of the latest features
- oh, and it keeps the bits that no one actually cares much about (the sequential version number) as simple as possible — a numeric value that gets incremented, a stark contract to how in practice minor versions in semantic versioning still routinely break things; if you’re on «stable», that’s not allowed by definition, end of story
So, once you put all of it together, you get a very simple and elegant system, a bit like the combination of the images above:

- there will always be opposition with arguments along the lines of «don’t you want new non-breaking feature enhancements», which is highly situational and actually might be what you’re after
- in practice, some companies out there have overcomplicated release strategies, like 4 or 5 parallel feature releases, each released and tested separately — this approach sadly allows you to do that with the TYPE values, which can match said features, e.g. 2021-stable-24, 2021-tournaments-244, 2021-judging-241, which i’d personally avoid; feature branches are for version control only, don’t fragment your release strategy that much
- you can still go from 2021-latest-343 to 2021-stable-216, which in the context of this particular changeset seems nonsensical, 343 shouldn’t be followed by 216; however this is by design, since if you’d attempt to increment the stable version number, you’d oftentimes skip numbers, or alternatively would put yourself in a world of hurt once your stable versions would get ahead of the latest ones but you’d still need to merge something from latest into the stable version; this remains unacknowledged as an actual problem
- the above approach won’t magically make your code more stable in of itself, you still only should commit «mostly stable» code to branches that you’ll release, with special care given to the «stable» release type; alas, your feature branches still are the ones that can be unstable, but need to have any problems addressed before being merged and released
- furthermore, there’s the implication that around the turn of the year you’d probably set aside anywhere from a month to a quarter of a year towards fixing the outstanding technical debt, so that your next «stable» release can live up to its name upon being released to the public; frankly, it’s probably not necessary for the projects that keep on top of their technical debt and pay it back as they’re developing their software, but in my experience those are about as rare as unicorns
Summary
In summary, looking at the above, i think i’ve basically described how and why Git branches with some additional tag information should be used as a basis for versioning as opposed to semantic versioning with its abstraction that doesn’t really conform to how branching works, nor is reflected well upon by the abilities of the average developer to recognize the difference between a minor version and a patch.
Actually, i don’t think that that’s a bad thing and would definitely lessen the cognitive load. I actually remember rather liking how SVN had numbered revisions which seemed more reasonable than Git hashes for figuring out how sequential changes happened. If Git and its branches get us most of the way there already, why not just stand on the shoulders of giants and throw in some easily automated text generation for the CI server to take care of, whilst remembering just a few very simple rules?
Update
Someone was kind enough to link this article on Hacker News, here’s an excerpt from my comment that attempts to provide a tl;dr for what my issues with semantic versioning are, in case any of you would find that to be more readable: