Versioning Guidelines
Fedora’s package versioning scheme
encompasses both the Version
and Release
tags, as well as Epoch
.
The overriding goal is to provide sequences of packages
which are treated as updates by RPM’s version comparison algorithm
while accommodating varied and often inconsistent upstream versioning schemes.
Some definitions
Note that upstreams may each have their own terminology and it is in general impossible to define these terms with complete generality. For some upstreams, every commit is itself considered a version. Some upstreams never make releases, instead just letting users take whatever is in the code repository at any given time.
- release version
-
A version of the software which upstream has decided to release. The act of releasing the software can be as simple as adding a git tag. This includes so-called "point releases" or "patch levels" which some upstreams make, since those are actually assigned versions and released.
- pre-release version
-
Before a release happens, some upstreams will decide which version that release will have, and then produce "alphas", "betas", "release candidates", or the like which carry that new version but indicate that the release of that version has not yet been made. These are known as pre-release versions.
- post-release version
-
This is similar to pre-release versions, but less common. Functionally these can be treated like a later point release. The important part to ensure they sort after the release version they are relative to, but before any version that upstream intends to supercede them.
- snapshot
-
An archive taken from the upstream’s source code management system that is not directly associated with any release version.
- post-release snapshot
-
A snapshot that is a later revision of the code than an existing release version. This kind of snapshot will often identify itself in code or metadata as the previous release version.
- pre-release snapshot
-
A snapshot that is an earlier revision of the code than a future release version, or than a future pre-release version. This kind of snapshot will often identify itself in code or metadata as the future release version.
- non-sorting version sequence
-
A sequence of version strings which is not ordered in the same way that RPM’s version comparison function would order it. RPM has a somewhat complicated version comparison function which it will use to determine if a package is "newer". If upstream’s idea of what constitutes a "newer" version differs from RPM’s implementation then simply using upstream’s versions directly will result in updates which don’t actually update any packages.
Epoch
tag
The Epoch
tag provides the most significant input to RPM’s version comparison function.
It is primarily used to force correct sorting of otherwise non-sorting version sequences from upstream.
Most packages will never need to use this tag.
If present, it MUST consist of a positive integer.
It SHOULD only be introduced or incremented
when necessary to avoid ordering issues.
The Epoch
tag, once introduced to a package,
MUST NOT ever be removed or decreased.
Version
tag
The Version
tag SHOULD contain the upstream project version.
This tag MAY diverge from the upstream project version when necessary for the following reasons:
-
enforce proper upgrade sorting
-
remove/replace invalid characters
-
include snapshot information (see the Snapshots section below)
Release
tag
The Release
tag SHOULD be managed automatically using the %autorelease
macro:
Release: %autorelease
As described in
%autorelease documentation,
the build machinery will
replace the macro with the number of builds since the last commit that changed the Version
tag,
suffixed with the %{?dist}
tag.
This means that a commit that changes Version
automatically gets Release: 1%{?dist}
,
and commits after that get Release: 2%{?dist}
, Release: 3%{?dist}
, and so on.
Alternatively, the Release
field MAY be updated manually.
See the legacy versioning section below.
Simple versioning
Most upstream versioning schemes are "simple";
they generate versions like 1.2
or 2024.09.06
.
They consist of one or more version components, separated by periods.
Each component is a whole number, potentially with leading zeroes.
The components can also include one or more ASCII letters, upper or lower case.
The value of a component MUST NOT ever be reduced (to a value which sorts lower)
without a component somewhere to the left increasing.
Note that the version sequence (1.4a
, 1.4b
, 1.4
)
does not meet this criterion,
as 4
sorts lower than 4b
.
If that sequence was instead (1.4
, 1.4a
, 1.4b
),
it would be simple and valid.
To package release versions of software using simple versioning,
use the upstream project version verbatim in the Version
tag.
Do not trim leading zeroes.
Complex versioning
There are several ways in which the simple versioning scheme might not work in a particular situation:
-
Upstream has never chosen a version.
-
You wish to package a snapshot.
-
You wish to package a pre-release version.
-
Upstream doesn’t use a version scheme which orders properly under RPM’s version comparison operation.
-
Upstream changed their version scheme in a way that does not sort properly.
-
You need to apply a small fix to a release branch of Fedora without updating the newer branches.
-
More than one of the above may apply (lucky you). Follow all of the relevant recommendations below together.
This subsection describes how to modify the upstream project version to be suitable for the Version
tag.
Use of Release: %autorelease
remains unchanged.
Character replacements
Some upstreams will release "post" or "patch" versions after a regular version but before the next regular version.
These can usually be handled with simple versioning with some slight adjustments.
Any invalid characters
MUST be replaced or removed.
A packager MAY replace the valid separator characters underscore (_
) and plus (+
) with periods.
For example, with upstream releases 0.5.0
, 0.5.0-post1
, and 0.5.1
,
the "post-release" version should use 0.5.0.post1
in the Version
tag.
Note that 0.5.0.post1
sorts lower than both 0.5.1
and 0.5.0.1
.
Non-sorting pre-release versions
A tilde (~
) is used before a version component which must sort earlier than any non-tilde component.
It is used for any pre-release versions which wouldn’t otherwise sort appropriately.
It is also used for pre-release snapshots, which is covered in the next section.
For example, with upstream releases 0.4.0
, 0.4.1
, 0.5.0-rc1
, 0.5.0-rc2
, 0.5.0
,
the two "release candidates" should use 0.5.0~rc1
and 0.5.0~rc2
in the Version
tag.
Snapshots
A package using a snapshot MUST use the following format for the Version
tag.
Version: <base-version><sort-character><number>.<revision>
-
<base-version>
: The version the snapshot is relative to. The snapshot will often identify itself in code or metadata as this version. -
<sort-character>
: A tilde (~
) for a pre-release snapshot, or a caret (^
) for a post-release snapshot. -
<number>
: An integer that is used for sorting multiple consecutive snapshots. This integer SHOULD be 1 for the first snapshot after a non-snapshot version, and incremented for each subsequent snapshot until the next non-snapshot version. You MAY instead use a date in eight-digit "YYYYMMDD" format, specifying the last modification to the source code. Note that using a date instead of a simple incrementing integer means you cannot release two snapshots from the same day. -
<revision>
: An identifier corresponding to the precise revision in the upstream source code management system. Some examples include a short git commit hash or a subversion revision number. If the upstream uses multiple source code management systems, use the revision from the primary one. If the source code management system does not provide an identifier (e.g. CVS), this part should be omitted. To avoid overly long versions, limit the revision to the first 7 to 10 characters instead of the full hash.
For example,
if you want to package a snapshot from commit a1b2c3d
that was made after version 0.4.1
,
the Version
tag would be 0.4.1^1.a1b2c3d
.
Note that 0.4.1^<something>
sorts higher than 0.4.1
,
but lower than both 0.4.2
and 0.4.1.<anything>
.
Similarly,
if you want to package a snapshot from commit d3c2b1a
that is leading up to version 0.4.2
,
the Version
tag would be 0.4.2~1.d3c2b1a
.
Note that 0.4.2~<something>
sorts lower than 0.4.2
,
but higher than both 0.4.1
and 0.4.1.<anything>
.
You can also package a snapshot following a pre-release version.
If the upstream makes a pre-release version 0.5.0-rc1
,
but you want to package a snapshot from commit a3b2c1d
that occured afterwards
(but still before the 0.5.0
version),
the Version
tag would be 0.5.0~rc1^1.a3b2c1d
.
Upstream has never chosen a version
When upstream has never chosen a version,
you MUST use a base version of 0
,
followed by pre-release snapshot notation.
Version: 0
.
“0” sorts lower than any other possible value that upstream might choose.
If upstream does choose to release "version 0",
then just set Release:
higher than the previous value.
(When %autorelease
is used, this happens automatically.)
Upstream uses invalid characters in the version
It’s possible that upstream uses characters besides ASCII letters (upper and lower case), digits and periods in its version. They must be removed and potentially replaced with valid characters. Any such alterations MUST be documented in the specfile. It is not possible to cover all potential situations here, so it is left to the packager to alter the upstream versioning scheme consistently.
After altering the version to be free of invalid characters, see Unsortable versions below if the modifications, when applied to successive releases from upstream, will not order properly.
Unsortable versions
When upstream uses a versioning scheme that does not sort properly, first see if simply inserting a tilde or caret is enough to make the string sortable.
For example, if upstream uses a sequence like 1.2pre1
, 1.2pre2
, 1.2final
,
then 1.2~pre1
, 1.2~pre2
, 1.2_final
could be used as Version
.
The underscore (‘_’) is a visual separator that does not influence sort order,
and is used here because "final" does not form a separate version component.
If this is not possible, use something similar to the snapshot version information field described above,
with the upstream version moved to the second part of the snapshot information field:
<date>.<version>
.
For example, if upstream releases versions I
, II
, …, VIII
, IX
use 20200101.I
, 20200201.II
, …, 20200801.III
, 20200901.IX
in the Version
tag.
Upstream breaks version scheme
It is possible that upstream simply adopts a different versioning scheme,
fails to follow an expected pattern,
or even simply resets their version to some lower value.
If none of the above operations can help
with giving a version which sorts properly,
or give you a version which sorts lower
than the packages already in Fedora,
then you have little recourse but to increment the Epoch:
tag,
or to begin using it by adding Epoch: 1
.
At the same time, try to work with upstream
to hopefully minimize the need to involve Epoch:
in the future.
Examples
Comparing versions with rpmdev-vercmp
When in doubt, verify the sorting with rpmdev-vercmp
from the rpmdevtools
package:
$ rpmdev-vercmp 2~almost^post 2.0.1
2~almost^post < 2.0.1
Simple versioning
Upstream version | Version tag | Explanation |
---|---|---|
1.0 |
1.0 |
The first release. |
1.1 |
1.1 |
An upstream update. |
1.2.1 |
1.2.1 |
Another upstream update. Extra levels of versioning are OK… |
1.3 |
1.3 |
…they can come and go without problems. |
In this case the full N-V-R could be e.g. pkg-1.2.1-1.fc38
(immediately after an update)
or pkg-1.2.1-5.fc38
(after downstream rebuilds with the same upstream version).
Upstream version | Version tag | Explanation |
---|---|---|
5.2 |
5.2 |
Upstream release. |
5.2a |
5.2a |
Upstream introduced a letter to indicate a patch release. You trust upstream to use letters in alphabetical order, so it’s OK to use the version as is. |
5.2b |
5.2b |
Another patch release after 5.2 — this is not a beta. |
5.2b.1 |
5.2b.1 |
Even this is OK as long as the sequence increases. |
5.3 |
5.3 |
Another upstream release. |
In this case the full N-V-R could be e.g. pkg-5.2b.1-1.fc38
.
Complex versioning with a reasonable upstream
Upstream version | Version tag | Notes |
---|---|---|
1.0.0-rc1 |
|
first pre-release |
1.0.0-rc2 |
|
second pre-release |
1.0.0 |
|
release |
1.0.1 |
|
bugfix release |
1.0.1-security1 |
|
security bufix release |
In this case the full N-V-R could be e.g. pkg-1.0.0~rc2-42.fc38
(if many rebuilds were done).
Complex versioning with non-sorting upstream post-release versions
Upstream version | Version tag | Notes |
---|---|---|
1.1.0~BETA |
|
this is a pre-release, first beta |
1.1.0~BETA1 |
|
this is a pre-release, second beta |
1.1.0~BETA2 |
|
this is a pre-release, third beta |
1.1.0~CR1 |
|
this is a pre-release, candidate release 1 |
1.1.0~CR2 |
|
this is a pre-release, candidate release 2 |
1.1.0-1% |
|
final release |
1.1.0-GA1 |
|
post release, GA1 |
1.1.0-CP1 |
|
post release, CP1, after GA1, does not sort properly |
1.1.0-CP2 |
|
post release, CP2, after CP1 |
1.1.0-SP1 |
|
post release, SP1, after CP2 |
1.1.0-SP1-CP1 |
|
post release, SP1_CP1, after SP1 |
In this case the full N-V-R could be e.g. pkg-1.1.0.20210105.SP1_CP1-1.fc38
.
Complex versioning with a pre- and post-release snapshots
Upstream version | Version | Notes |
---|---|---|
1.0.0-rc1 |
|
First pre-release |
1.0.0-rc2 |
|
Second pre-release |
git commit |
|
Post pre-release snapshot |
1.0.0 |
|
A release |
1.0.1 |
|
A bugfix release |
git commit |
|
A snapshot |
1.0.1-security1 |
|
A security bufix release. From past history we know that the bugfix releases will have sortable versions. If not, we could use ‘<date>.security1’ instead. |
git commit |
|
Another snapshot |
In this case the full N-V-R could be e.g. pkg-1.0.1.security1^20210301gabc0202-1.fc38
.
Legacy versioning with part of the upstream version information in the Release tag
The method described in this section is deprecated, but MAY be used. As mentioned in the Handling non-sorting versions with tilde, dot, and caret section above, this method is recommended for packages with complex versioning when supporting RHEL7 and other systems with old rpm versions.
In this method, %autorelease
is not used, and the Release
tag must be managed manually.
This method for dealing with most pre- and post-release versions and unsortable versions
involves potentially removing some information from the Version:
tag
while imposing additional structure onto the Release:
tag.
There are potentially four sections which comprise
the structured Release
tag:
-
package release number (
<pkgrel>
) -
extra version information (
<extraver>
) -
snapshot information (
<snapinfo>
) -
minor release bump (
<minorbump>
)
The package release number MUST always be present while the others may or may not be depending on the situation.
Those items which are present are combined
(with periods to separate them)
to construct the final Release:
tag.
In the usual notation where
square brackets indicate that an item is optional:
<pkgrel>[.<extraver>][.<snapinfo>]%{?dist}[.<minorbump>]
The actual values to be used for those three sections are situational
and are referenced in the sections below.
Note that your particular situation might not result
in the use of <extraver>
or <snapinfo>
,
and in most situations <minorbump>
won’t be used at all.
Simply do not include those which you don’t have.
Note that the dist tag is supplied by other portions of the system
and may in some circumstances contain additional structure,
including tildes.
As this is not under the control of the packager,
that structure is not covered here.
The packager MUST simply include %{?dist}
verbatim
as indicated above.
Unsortable versions
When upstream uses a versioning scheme that does not sort properly,
first see if there is any portion which can be removed
from the right side of the version string
such that the remainder is sortable.
This is often possible if upstream uses a sequence like
("1.2pre1", "1.2pre1", "1.2final").
If so, use the removed portion as <extraver>
above,
and the remainder as the package version.
If this splitting leaves a leading or trailing period in either value,
remove it.
If this is not possible,
use Version: 0 and move the entire version string into <extraver>
.
Snapshots
All snapshots MUST contain a snapshot information field
(<snapinfo>:
) in the Release:
tag.
That field must at minimum consist of the date
in eight-digit "YYYYMMDD" format.
The packager MAY include
up to 17 characters of additional information
after the date.
The following formats are suggested:
-
YYYYMMDD.<revision>
-
YYYYMMDD<scm><revision>
Where <scm>
is a short string
identifying the source code management system upstream uses
(e.g. "git", "svn", "hg")
or the string "snap".
<revision>
is either
a short git commit hash,
a subversion revision number,
or something else useful in identifying the precise revision
in upstream’s source code management system.
Obviously if CVS is used,
no such revision information exists,
so it would be omitted,
but otherwise it SHOULD be included.
Pre-release versions
In the Version
tag,
use the version that upstream has determined the next release will be.
For the field of the Release
tag,
use a number of the form "0.N"
where N is an integer beginning with 1
and increasing for each revision of the package.
Pre-release versions MUST use
a Release:
tag strictly less than 1,
as this is the sole indicator that a pre-release has been packaged.
Release and post-release versions
For the <pkgrel>
field of the Release:
tag,
use an integer beginning with 1
and increasing for each revision of the package.
Release and post-release versions MUST use
a Release:
tag greater than or equal to 1.
Rebuilds in older branches using <minorbump>
In the situation described in [Only an old branch needs a change],
you MAY adjust the Release
by appending a number after the dist tag,
creating a E-V-R for F38 that still compares lower than the one in F39.
Set <minorbump>
to an in integer beginning with '1'
and increase it by one for each minor bump you need to do.
Remove <minorbump>
once you are able
to increase the package release normally
without introducing ordering issues.
Examples
Examples of many possible versioning scenarios of traditional versioning are available from Package Versioning Examples.
Rawhide is allowed to lag temporarily
A package MAY temporarily have a lower EVR in Rawhide when compared to a release branch of Fedora ONLY in the case where the package fails to build in Rawhide. This permits important updates to be pushed to existing Fedora releases regardless of the current state of Rawhide.