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 "patchlevels" which some upstreams make, since those are actually assigned versions and released.

snapshot

An archive taken from upstream’s source code control system which is not associated with any release version.

prerelease version

Before a release happens, many upstreams will decide which version that will 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 we call prerelease versions. Any snapshots made while upstream is preparing for their release are also considered prerelease versions.

postrelease version

Any version which happens after a particular release is technically "post-release", but before upstream begins making prereleases for the next version, any snapshot is considered a postrelease 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. 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 never be removed or decreased.

Simple versioning

Most upstream versioning schemes are "simple"; they generate versions like 1.2.03.007p1. 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 never 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. The sequence (1.4, 1.4a, 1.4b) is, however, simple.

This is a very common versioning scheme, and the vast majority of software projects use something which works like this.

To package release versions of software using this versioning scheme:

  • Use the upstream verbatim in the Version: tag. Don’t trim leading zeroes.

  • Use a Release: tag starting with 1 (never 0). Append the Dist Tag. Increment the release (by 1) for each update you make. Reset to 1 whenever you change Version:.

Complex versioning

There are several ways in which the simple scheme might not work in a particular situation:

  • Upstream has never chosen a version; only snapshots are available for packaging.

  • Upstream simply doesn’t use a version scheme which orders properly under RPM’s version comparison operation.

  • You wish to package a prerelease version (snapshot or otherwise).

  • You wish to package a postrelease snapshot.

  • Upstream was thought to be following one scheme but then changed 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.

Handling non-sorting versions with tilde, dot, and caret

The tilde symbol (‘~’) 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.

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: field.

Bugfix or "patchlevel" releases that some upstream make should be handled using simple versioning. The separator used by upstream may need to be replaced by a dot or dropped.

For example, if the same upstream released 0.5.0-post1 as a bugfix version, this "post-release" should use 0.5.0.post1 in the Version: field. Note that 0.5.0.post1 sorts lower than both 0.5.1 and 0.5.0.1.

The caret symbol (‘^’) is used before a version component which must sort later than any non-caret component. It is used for post-release snapshots, see next section.

The caret operator is not supported in RHEL7 which has rpm 4.11. If you need to support RHEL7/EPEL7 from the same specfile, use [Traditional versioning with part of the upstream version information in the release field] instead.

Snapshots

Snapshots (a version taken from the upstream source control system not associated with a release), must contain a snapshot information field after a caret (^). The first part of the field ensures proper sorting. That field may either the date in eight-digit "YYYYMMDD" format, which specifies the last modification of the source code, or a number. The packager may include up to 17 characters of additional information after the date, specifying the version control system and commit identifier. The snapshot information field is appended to version field described above, possibly including the pre-release and patchlevel information.

One of the following formats should be used for the snapshot information field:

  • <date>.<revision>

  • <date><scm><revision>

  • <number>.<revision>

  • <number>.<scm><revision>

Where <scm> is a short string identifying the source code control system upstream uses (e.g. "git", "svn", "hg") or the string "snap". The <scm> string may be abbreviated to a single letter. <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 control system. If the version control system does not provide an identifier (e.g. CVS), this part should be omitted. A full hash should not be used for <revision>, to avoid overly long version numbers; only the first 7 to 10 characters.

For example, if the last upstream release was 0.4.1, a snapshot could use 0.4.1^20200601g01234ae in the Version: field. Similarly, if the upstream then makes a pre-release with version 0.5.0-rc1, but it is buggy, and we need to actually package two post-pre-release snapshots, those shapshots could use 0.5.0~rc1^20200701gdeadf00f and 0.5.0~rc1^20200702gdeadaeae in the Version: field.

Alternatively, those three snapshots could be versioned as 0.4.1^1.git01234ae, 0.5.0~rc1^1.gitdeadf00f and 0.5.0~rc1^2.gitdeadaeae.

Note that 0.4.1^<something> sorts higher than 0.4.1, but lower than both 0.4.2 and 0.4.1.<anything>.

Upstream has never chosen a version

When upstream has never chosen a version, you must use 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.

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 field.

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:

==== Simple versioning

[%header]
|===
|Upstream| Version field | Release field | Explanation

|1.0     |1.0         | 1%{?dist} | The first release.

|1.1     |1.1         | 1%{?dist} | An upstream update.

|1.1     |1.1         | 2%{?dist} | You made a change to the package but the upstream version didn't change.

|1.2     |1.2         | 1%{?dist} | The upstream version changed, so Release: goes back to 1.

|1.2.1   |1.2.1       |1%{?dist}  | Extra levels of versioning are OK…

|1.3     |1.3         |1%{?dist}  | …they can come and go without problems.
|===

[%header]
|===
|Upstream| Version field | Release field | Explanation

| 5.2    | 5.2           | 1%{?dist}     |

| 5.2a   | 5.2a          | 1%{?dist}     | 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          | 1%{?dist}     |

| 5.2b.1 | 5.2b.1        | 1%{?dist}     | Even this is OK as long as the sequence increases.

| 5.3    | 5.3           |  1%{?dist}    |
|===

==== Complex versioning with a reasonable upstream

[%header]
|===
|Upstream version | Full package NEVRA | Notes

| 1.0.0-rc1 | `+pkg-1.0.0~rc1-1%{?dist}+` | first prerelease

| 1.0.0-rc2 | `+pkg-1.0.0~rc2-1%{?dist}+` | second prerelease

| 1.0.0     | `+pkg-1.0.0-1%{?dist}+`     | release

| 1.0.1     | `+pkg-1.0.1-1%{?dist}+`     | bugfix release

| 1.0.1-security1 | `+pkg-1.0.1.security1-1%{?dist}+` | security bufix release
|===

==== Complex versioning with non-sorting upstream post-release versions

[%header]
|===
|Upstream version | Full package NEVRA | Notes

| 1.1.0~BETA      | `+pkg-1.1.0~BETA-1%{?dist}+` | this is a prerelease, first beta

| 1.1.0~BETA1     | `+pkg-1.1.0~BETA1-1%{?dist}+` | this is a prerelease, second beta

| 1.1.0~BETA2     | `+pkg-1.1.0~BETA2-1%{?dist}+` | this is a prerelease, third beta

| 1.1.0~CR1       | `+pkg-1.1.0~CR1-1%{?dist}+` | this is a prerelease, candidate release 1

| 1.1.0~CR2       | `+pkg-1.1.0~CR2-1%{?dist}+` | this is a prerelease, candidate release 2

|                 | `+pkg-1.1.0~CR2-2%{?dist}+` | this is a prerelease, candidate release 2, second build

| 1.1.0-1%        | `+pkg-1.1.0-1%{?dist}+` | final release

| 1.1.0-GA1       | `+pkg-1.1.0.20201001.GA1-1%{?dist}+` | post release, GA1

| 1.1.0-CP1       | `+pkg-1.1.0.20201011.CP1-1%{?dist}+` | post release, CP1, after GA1, does not sort properly

| 1.1.0-CP2       | `+pkg-1.1.0.20201101.CP2-1%{?dist}+` | post release, CP2, after CP1

| 1.1.0-SP1       | `+pkg-1.1.0.20210101.SP1-1%{?dist}+` | post release, SP1, after CP2

| 1.1.0-SP1-CP1   | `+pkg-1.1.0.20210105.SP1_CP1-1%{?dist}+` | post release, SP1_CP1, after SP1
|===


==== Complex versioning with a pre- and post-release snapshots

[%header]
|===
|Upstream version | Full package NEVRA | Notes

| 1.0.0-rc1            | `+pkg-1.0.0~rc1-1%{?dist}+` | First prerelease

| 1.0.0-rc2            | `+pkg-1.0.0~rc2-1%{?dist}+` | Second prerelease

| git commit `f00fabd` | `+pkg-1.0.0~rc2^20210101gf00fabd-1%{?dist}+` | Post-prerelease snapshot

| 1.0.0                | `+pkg-1.0.0-1%{?dist}+`     | A release

|                      | `+pkg-1.0.0-2%{?dist}+`     | A rebuild from the same sources

| 1.0.1                | `+pkg-1.0.1-1%{?dist}+`     | A bugfix release

| git commit `bbbccc0` | `+pkg-1.0.1^20210203gbbbccc0-1%{?dist}+` or `+pkg-1.0.1^1.gbbbccc0-1%{?dist}+` | A snapshot

| 1.0.1-security1      | `+pkg-1.0.1.security1-1%{?dist}+` | 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 `abc0202` | `+pkg-1.0.1.security1^20210301gabc0202-1%{?dist}+` or `+pkg-1.0.1.security1^1.gabc0202-1%{?dist}+` | Another snapshot
|===


== Traditional versioning with part of the upstream version information in the release field

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.

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 fields 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 fields 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 control 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 control system. Obviously if CVS is used, no such revision information exists, so it would be omitted, but otherwise it **should** be included.

=== Prerelease 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. Prerelease versions **must** use a `+Release:+` tag strictly less than 1, as this is the sole indicator that a prerelease 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.

=== Examples

Examples of many possible versioning scenarios of traditional versioning are available from https://fedoraproject.org/wiki/Package_Versioning_Examples[Package Versioning Examples].





== You need to change an old branch without rebuilding the others

Sometimes, you may find yourself in a situation where an older branch needs a fix, but the newer branches are fine. For example, if a package has a version-release of `+1.0-1%{?dist}+` in F{CURRENTVER} and F{NEXTVER}, and only F{CURRENTVER} needs a fix. Normally, you would need to bump the release in each of the branches to ensure that F{CURRENTVER} < F{NEXTVER}, but that is a waste of time and energy for the newer branches which do not need to be touched.

In this case, you **may** set `+<minorbump>+` to an in integer beginning with '1' and increasing 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.


== 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.