5.6 Comparing Versions

Two version strings are compared in three stages:

  1. Compare epochs as integers. If they differ, the higher epoch is greater.
  2. If equal, compare upstream versions by the algorithm below.
  3. If equal, compare peios revisions as integers. The higher revision is greater.
  4. If all three are equal, the versions are equal.

5.6.1 Tokenising the upstream version #

A tokeniser walks the upstream string left to right and emits segments:

  1. The non-alphanumeric characters ., +, -, and ~ are separators and belong to no segment.
  2. A maximal run of digits forms a numeric segment.
  3. A maximal run of letters forms an alphabetic segment.
  4. A transition between a digit and a letter ends the current segment and begins a new one.

5.6.2 Pre-release segments #

A segment is a pre-release segment if it falls at or after the earlier of:

  • the first ~ separator — the tilde and every segment following it; or
  • the first recognised pre-release token: a segment whose token carries a rank of 0 to 4 in the table below, that segment and every segment following it.

Once the pre-release tail begins it extends to the end of the upstream version: every later segment is a pre-release segment, whatever the separators between them. A - separator is an ordinary separator; it is not itself a pre-release marker.

UpstreamSegments
1.26.21, 26, 2
1.0.0-rc.11, 0, 0, rc (pre), 1 (pre)
1.0~rc11, 0, rc (pre), 1 (pre)
16beta116, beta (pre), 1 (pre)

5.6.3 Pre-release rank #

TokenRank
dev0
alpha1
a1
beta2
b2
pre3
rc4
any other alphabetic token5

Rank 0 sorts lowest. Rank lookup MUST be case-insensitive: Alpha, ALPHA, and alpha all carry rank 1.

5.6.4 Comparing two segments #

The pre-release flag is compared first, before the kinds. If exactly one of the two segments is a pre-release segment, that segment is the lesser, whatever either segment contains. A pre-release segment sits at or after the point where the version was marked as preceding a release, and that is a property of position rather than of content.

When both segments carry the same flag — both pre-release, or neither — their kinds decide:

  1. Both numeric — compare as integers. Leading zeros are insignificant.
  2. Both alphabetic — compare by pre-release rank. When the ranks are equal:
    • at a rank of 0 to 4, the segments are equivalent. The table assigns several tokens to one rank as aliases, so two segments at the same recognised rank sort equal whichever alias appears.
    • at rank 5, the segments tiebreak by ASCII byte order against other rank-5 tokens.
  3. One numeric, one alphabetic — the alphabetic segment is the lesser if the pair is a pre-release pair, and the greater if it is not. (Where only one of them is a pre-release segment, the rule above has already decided.)

5.6.5 Unequal lengths #

When the segments of one version run out and every common segment compared equal, the next segment of the longer sequence decides. Its pre-release flag decides it, and its kind is irrelevant:

Next segment in the longerResult
a pre-release segmentthe shorter is greater
anything elsethe shorter is less
Example tailResult
~1numeric, pre-releasethe shorter is greater
~rcalphabetic, pre-releasethe shorter is greater
.1numericthe shorter is less
-fooalphabetic, rank 5the shorter is less

5.6.6 Worked examples #

ABResultWhy
1.0~21.0-2A < Bthe pre-release flag decides before the kinds
1.0~foo1.0-fooA < Bthe same, for two rank-5 tokens
1.01.0A = Bidentical
1.02.0A < Bnumeric segment differs
1.101.9A > Bnumeric, not lexical
1.01.0.1A < Blonger continues numerically
1.01.0-rc.1A > Blonger continues with a pre-release
1.0-rc.11.0-rc.2A < Bnumeric segment within the tail
1.0-alpha1.0-betaA < Brank 1 < rank 2
1.0-rc1.0-preA > Brank 4 > rank 3
1.0a11.0a2A < Bnumeric within a concatenated tail
1.0a11.0b1A < Brank 1 < rank 2
1.0~rc11.0A < Bthe tilde forces a pre-release
1.0~11.0A < Bthe tilde forces a pre-release, numeric or not
5.2~202401015.2A < Ba dated snapshot precedes its release
0:1.01:0.5A < Bepoch dominates
1.0-11.0-2A < Bpeios revision differs
1.0-foo-11.0-1A > Bfoo is rank 5, sorting after a number

Edit this page