5.6 Comparing Versions
Two version strings are compared in three stages:
- Compare epochs as integers. If they differ, the higher epoch is greater.
- If equal, compare upstream versions by the algorithm below.
- If equal, compare peios revisions as integers. The higher revision is greater.
- 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:
- The non-alphanumeric characters
.,+,-, and~are separators and belong to no segment. - A maximal run of digits forms a numeric segment.
- A maximal run of letters forms an alphabetic segment.
- 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.
| Upstream | Segments |
|---|---|
1.26.2 | 1, 26, 2 |
1.0.0-rc.1 | 1, 0, 0, rc (pre), 1 (pre) |
1.0~rc1 | 1, 0, rc (pre), 1 (pre) |
16beta1 | 16, beta (pre), 1 (pre) |
5.6.3 Pre-release rank #
| Token | Rank |
|---|---|
dev | 0 |
alpha | 1 |
a | 1 |
beta | 2 |
b | 2 |
pre | 3 |
rc | 4 |
| any other alphabetic token | 5 |
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:
- Both numeric — compare as integers. Leading zeros are insignificant.
- 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.
- 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 longer | Result |
|---|---|
| a pre-release segment | the shorter is greater |
| anything else | the shorter is less |
| Example tail | Result | |
|---|---|---|
~1 | numeric, pre-release | the shorter is greater |
~rc | alphabetic, pre-release | the shorter is greater |
.1 | numeric | the shorter is less |
-foo | alphabetic, rank 5 | the shorter is less |
5.6.6 Worked examples #
| A | B | Result | Why |
|---|---|---|---|
1.0~2 | 1.0-2 | A < B | the pre-release flag decides before the kinds |
1.0~foo | 1.0-foo | A < B | the same, for two rank-5 tokens |
1.0 | 1.0 | A = B | identical |
1.0 | 2.0 | A < B | numeric segment differs |
1.10 | 1.9 | A > B | numeric, not lexical |
1.0 | 1.0.1 | A < B | longer continues numerically |
1.0 | 1.0-rc.1 | A > B | longer continues with a pre-release |
1.0-rc.1 | 1.0-rc.2 | A < B | numeric segment within the tail |
1.0-alpha | 1.0-beta | A < B | rank 1 < rank 2 |
1.0-rc | 1.0-pre | A > B | rank 4 > rank 3 |
1.0a1 | 1.0a2 | A < B | numeric within a concatenated tail |
1.0a1 | 1.0b1 | A < B | rank 1 < rank 2 |
1.0~rc1 | 1.0 | A < B | the tilde forces a pre-release |
1.0~1 | 1.0 | A < B | the tilde forces a pre-release, numeric or not |
5.2~20240101 | 5.2 | A < B | a dated snapshot precedes its release |
0:1.0 | 1:0.5 | A < B | epoch dominates |
1.0-1 | 1.0-2 | A < B | peios revision differs |
1.0-foo-1 | 1.0-1 | A > B | foo is rank 5, sorting after a number |