05 марта 2026 № 1 (2026)

ROSARIUM

газета советского программиста

Версионирование и Epoch

Как rpm сравнивает версии и когда нужен Epoch.

На этой странице

Правильное версионирование гарантирует, что dnf upgrade обновит пакет корректно. Ошибки в версионировании — одни из самых сложных в исправлении.

Как RPM сравнивает версии

Полная версия пакета — это Epoch:Version-Release (EVR).

Приоритет сравнения:

  1. Epoch (наивысший приоритет)
  2. Version
  3. Release
# Проверить порядок версий
rpmdev-vercmp 1.0-1 1.1-1
# 1.0-1 < 1.1-1

rpmdev-vercmp 1:1.0-1 2.0-1
# 1:1.0-1 > 2.0-1  (Epoch 1 больше неявного Epoch 0)

Алгоритм сравнения Version

RPM разбивает строку версии на сегменты и сравнивает их:

1.12.3  →  [1] [12] [3]
1.9.10  →  [1] [9]  [10]

1 == 1
12 > 9   →  1.12.3 > 1.9.10  (числовое сравнение!)

Числовые сегменты сравниваются как числа, строковые — лексикографически:

1.0a < 1.0b        (строковое: 'a' < 'b')
1.0.1 > 1.0        (больше сегментов)
1.0 == 1.0.0       (хвостовые нули игнорируются)

Release: версия упаковки

Version:        2.1.0
Release:        1%{?dist}

Правила:

  • При обновлении Version — сбрасывайте Release в 1
  • При изменении только SPEC (патч, зависимость) — увеличивайте Release
2.1.0-1.rosa13.1    ← Первая сборка версии 2.1.0
2.1.0-2.rosa13.1    ← Исправлен SPEC (добавлен патч)
2.1.0-3.rosa13.1    ← Ещё одно исправление
2.2.0-1.rosa13.1    ← Новая версия upstream

Предрелизные версии (alpha, beta, rc)

Проблема

Upstream выпускает 2.0-rc1, потом 2.0. Но RPM считает:

2.0.rc1 > 2.0    ← НЕПРАВИЛЬНЫЙ порядок!

Решение: тильда (~)

Тильда делает версию ниже финальной:

# Release Candidate — ниже 2.0
Version:        2.0~rc1
Release:        1%{?dist}

# Финальный релиз
Version:        2.0
Release:        1%{?dist}

Проверка:

rpmdev-vercmp 2.0~rc1-1 2.0-1
# 2.0~rc1-1 < 2.0-1  ✓

Правильный порядок:

2.0~alpha1 < 2.0~beta1 < 2.0~rc1 < 2.0 < 2.0.1

Каретка (^) — пост-релизные снапшоты

Каретка делает версию выше текущей, но ниже следующей:

# Снапшот после 2.0, но до 2.0.1
Version:        2.0^20250203gitabc1234
Release:        1%{?dist}
2.0 < 2.0^20250203gitabc1234 < 2.0.1

Снапшоты из git

Когда upstream не делает релизов, а нужна свежая версия из git:

Способ 1: через Release (традиционный)

%global commit abc1234def5678
%global shortcommit %(c=%{commit}; echo ${c:0:7})
%global gitdate 20250203

Version:        1.2
Release:        0.1.%{gitdate}git%{shortcommit}%{?dist}

0.X в Release гарантирует, что снапшот ниже будущего финального 1.2-1:

1.2-0.1.20250203gitabc1234  <  1.2-1

При следующем снапшоте:

Release:        0.2.%{gitdate}git%{shortcommit}%{?dist}

При выходе финального 1.2:

Release:        1%{?dist}

Способ 2: через каретку (современный)

Version:        1.1^20250203gitabc1234
Release:        1%{?dist}
1.1 < 1.1^20250203gitabc1234 < 1.2

Epoch: крайняя мера

Когда использовать

Epoch нужен только когда upstream ломает порядок версий:

Было:   2024.01.15   (версия по дате)
Стало:  1.0.0        (upstream перешёл на semver)

RPM считает 2024.01.15 > 1.0.0, поэтому dnf upgrade не обновит пакет.

Решение:

Epoch:          1
Version:        1.0.0
Release:        1%{?dist}

Теперь 1:1.0.0 > 0:2024.01.15.

Почему Epoch опасен

  • Нельзя убрать. Если добавили Epoch: 1, нельзя потом откатить на Epoch: 0
  • Заражает зависимости. Пакеты, зависящие от вашего, должны учитывать Epoch:
# Без Epoch
Requires: libfoo = 1.0.0

# С Epoch
Requires: libfoo = 1:1.0.0
  • Усложняет сопровождение навсегда

Альтернативы Epoch

Перед использованием Epoch попробуйте:

  1. Переформатировать Version:

    # Вместо Epoch
    Version:  20240115    →    Version:  1.0.0~20240115
    
  2. Использовать Obsoletes:

    Name:     mypackage
    Version:  1.0.0
    Obsoletes: mypackage < 2024.01.16
    

Сводка правил

СценарийЧто делать
Новая версия upstreamVersion: X.Y.Z, Release: 1%{?dist}
Исправление SPECУвеличить Release
Предрелиз (alpha/rc)Version: X.Y~rcN
Снапшот из gitRelease: 0.N.YYYYMMDD... или Version: X.Y^DATE...
Upstream сломал нумерациюEpoch (крайний случай)

Проверка порядка версий

# Сравнить две версии
rpmdev-vercmp 1.0-1 1.0-2
rpmdev-vercmp 2.0~rc1-1 2.0-1
rpmdev-vercmp 1:1.0-1 2.0-1

# Посмотреть NEVRA установленного пакета
rpm -q --queryformat '%{EPOCH}:%{VERSION}-%{RELEASE}\n' mypackage

Проверьте понимание

  1. Как RPM сравнивает версии 1.9 и 1.12?
  2. Что означает тильда в 2.0~rc1?
  3. Когда нужно сбрасывать Release в 1?
  4. Почему Release: 0.1.date... гарантирует порядок ниже финального релиза?
  5. Какие альтернативы Epoch можно попробовать?

Следующий модуль: Качество и релиз