mirror of
https://github.com/semver/semver.git
synced 2026-07-10 19:50:47 -05:00
[GH-ISSUE #630] Reasoning for "MUST" in resetting MINOR to zero? #6430
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @nolar on GitHub (Oct 23, 2020).
Original GitHub issue: https://github.com/semver/semver/issues/630
Can you please add a reason for "MUST" in the rule 8 into FAQ?
I've gone through almost all open & closed issues regarding this topic (phew! a lot!), and none contained a single explanation of "why". The closest of them all was the oldest one: #9, which only answers "how", or "what" in the best case, but not "why".
Please note that this question is not about CI build numbers or other "implementation details", but rather about the API compatibility and risk management, i.e. human-managed versions with meaning attached.
What specifically is wrong with the following sequence of versions from the "semantic" point of view?
0.12.00.13.01.14.01.15.02.16.0Each new release adds a feature: milestones 12-16 — or, better said, feature-sets 12-16. Some of these releases break some (but not all) of the APIs/protocols/promises, and therefore increase the major version, but continue in the same milestone sequence for minor versions. All the SemVer-compatible software will handle that properly (as if versions
1.0.0-1.13.0,2.0.0-2.15.0were released and instantly hidden/yanked).It might be convincing to follow the same resetting policy for minor & patch versions for the generalisation purposes, same as the time does with hours & minutes & seconds. But these version components have different semantics:
Semantically (i.e. "by meaning"), the patch versions (
x.y.1,x.y.2) are little addons on top of the foundation that represents functionality (x.y.0) — as essentially defined in the SemVer's Summary.However, the minor versions (
x.1.0,x.2.0) are semantically NOT addons on top of the foundation represented by thenewmodified API (x.0.0).Unlike the "patches", the functionality is continuous (in most cases). Unless it is a full remake of the library, in which case the "functionality" is revised, and the major version upgrade really means the reset of functionality, so it makes sense to semantically start with zero in those rare cases.
I'm not sure if it is worth asking to change the "MUST" word to "SHOULD" or "MAY" and let the developers decide. It was requested before, to no avail.
I also understand that to be formally compliant with SemVer, things MUST be done as written. But it would be good if the reasoning behind the rules or the spirit of the versioning schema is also explained.
Thanks for your attention.
@ljharb commented on GitHub (Oct 23, 2020):
tbh i think that's a great reason - so as to PROHIBIT people from inferring additional meaning from "the minor is steadily increasing, unrelated to the major/patch". Semver conveys breakage, and should not be used to convey anything else, including "feature-sets" or "milestones".
@nolar commented on GitHub (Oct 23, 2020):
Just to clarify: I didn't mean "unrelated to the patch". Quite the opposite — patches (defined as bugfixes — point 6 of the spec) are strictly bound to their relevant major.minor tuples (defined as functionality and APIs — points 7-8).
@ljharb commented on GitHub (Oct 23, 2020):
Sure, thanks for clarifying - but then you're still trying to squish additional semantic meaning into a semver version, beyond what semver is supposed to solely communicate.
@nolar commented on GitHub (Oct 23, 2020):
And that's the point of this issue and the trigger for it:
I inferred these meanings from the description of SemVer itself:
A transition from
0.13.0to1.14.0conveys the message that a few features were added, but "14" is nearly the same as "13", and we broke the API a bit. All of this is in line with the spirit of SemVer as seen by a naïve reader.Specifically, I didn't get how it (SemVer) goes from these declarations about its purpose to the specific rules on how to reset minor versions. Which makes me assume that maybe someone in the past just put their habits or preferences into it instead of the logical and consistent values — and that knowledge is now lost.
If that meaning is not supposed to be inferred, then the SemVer introduction and description are ambiguous, or not clear about what SemVer is NOT about or NOT for. — Hence the question.
However, if you state that SemVer is about breakage only, then the minor resets should not be covered/regulated at all, leaving them to the developers, should they?
I say this not for the purpose of having a fight or question your previous decisions (sorry if my question makes that impression and causes the defensive reaction), but rather to provide a point of view on how this specification can be read.
@ljharb commented on GitHub (Oct 23, 2020):
To be clear, I'm not a maintainer here and I've made no decisions :-) but to me, what I described seems like a reasonable reason for the restriction.
@ghost commented on GitHub (Oct 25, 2020):
I agree with both of you. The description of SemVer is much broader than the ruleset that it sets out to define. I think some updates are needed.
@AndreKR commented on GitHub (Oct 31, 2020):
Occasionally I find it useful to auto-generate the PATCH version from the number of commits between root and the release, causing it to increase steadily. I just found out that technically that's violating semver, and I'm also curious what the rationale behind the "MUST reset to zero" rule might be.
@jwdonahue commented on GitHub (Sep 6, 2021):
Perhaps nobody noticed, but there is a loop-hole to this reset issue, that is implicitly built into the spec. The spec says your version generator should follow the reset pattern:
0.1.0
...
1.0.0
...
2.0.0
But you are under no obligation to maintain that historical pattern in your release feeds. You are free to remove any version for any reason, so you could in practice, follow the OP's suggested pattern without breaking consumers, but there's nothing in the SemVer spec that provides any of the suggested new semantics that would be useful to consumers.
@jwdonahue commented on GitHub (Sep 6, 2021):
From the 3rd paragraph of the Introduction:
These conventions have their roots in common manufacturing practices of the mid 1900's, and those evolved from earlier practices that themselves evolved from the publishing industry. I remember when bills-of-materials for boards included PROM's burned from "golden PROM's" created at the desk of an EE/SD and hand carried down to the manufacturing floor. Due to paper or computer form design and internal company practices, version labels on those GPROM's often adhered to the Prod{#}-Rev{alpha|num} format. Later, pure software version numbers were usually just a counter that we had to remember to bump in a header file somewhere, until we figured out how to automate that process.
The pure software developers eventually rediscovered that there was a reason for the MajorVersion-Revision formats their predecessors used, and often resorted to using fixed or floating point numbers. Decades later, the Major.Minor.Patch format evolved from those. Resetting lower order fields to zero wasn't just a convention, it evolved from the fact that we had limited space to store values and we had to reset from 1.9 to 2.0 or we'd run out of storage or display space.
@jwdonahue commented on GitHub (Sep 6, 2021):
The fact that other semantic schemes can be mapped onto SemVer compliant strings and version histories, does not imply that SemVer should be modified to better accommodate or directly define them, or how they should be mapped onto SemVer. The spec, as it stands now, reflects the consensus view of stake-holders who maintain packaging/dependency tooling in common use. They are motivated to protect the status quo, which many argue is a good thing when it comes to standards.
Most of the SemVer compliant tooling also provide non-SemVer specific features, so you are often free to implement any scheme you see fit, and can often shoe-horn those into SemVer dependent ecosystems. Your mileage may vary.
@dylanopen commented on GitHub (Jul 23, 2025):
I'm 4 years late to this. But I just wanted to add some reasons as to why I think that not resetting the minor and patch versions is actually a good idea. I think @nolar is completely right.
Looking at the issue number for a very similar issue (#9) it's clear that it was realised very early on that not resetting the minor and patch versions could work.
So why do I think this is a good idea?
Not resetting any of the version segments allows you to easily tell the number of versions that have been released. If you have a project which uses this 'continuous version numbering' system, you can simply add up the major, minor and patch versions to find out exactly how many releases there have been.
It can also be used to tell how far along a project is in development. If you see something like
4.0.0, it's not clear as to whether it's had 4 released or 400, as the evidence of progress is essentially thrown away when resetting the minor and patch. Of course, project maturity shouldn't be judged based on the number of releases. But it's still a good way of telling roughly how mature a package is.As a library maintainer, I wouldn't like to go from, say, version
2.17.38to just3.0.0. Maybe it's just a psychological thing, but I think that a library would look better for users having3.17.38instead as it shows it's actually had more active development.It's easy to see exactly how many patches there have been, just look at the last number.
It's also easy to see exactly how many minor versions there have been, look at the middle number.
Most importantly, you can very easily see whether or not a library regularly introduces breaking change. If a library has been around for 5 years and has a major version of
4, it's probably more stable than one with a major version of82as it less frequently introduces breaking changes. (Before you comment, I know, you can still see this with 'resetting' semver. But most library maintainers will release breaking changes in 'big bundles' - I believe because of this notion of 'resetting the progress'. Continuous Semver, a term I will coin 😄, mostly gets rid of this issue.Why does it get rid of this issue? The biggest issue that semver has at the moment is library devs not wanting to push a new major version. They bundle up loads of breaking changes and push these all in one major release, making it really difficult for library users to update (as so much has changed).
I'm the developer of a Rust library called
Realms(https://github.com/dylanopen/realms). I use this continuous semver approach, because it allows me to push a new major version whenever I make a change, so it's really easy for my users to update (just changing a few function calls, usually).If I instead reset the minor and patch, I'd be much more weary of making major releases. That's because resetting any sort of versioning makes it feel like your losing progress. This is silly of course, but it's a real thing and the best we can do is try to make releasing major versions more normalised. Breaking change is never good, but it's much better to slowly release it rather than one huge change which makes migration near impossible.
This is of course my opinion. I'm well aware that most of my points ultimately come down to "bigger version numbers = shows more progress = good", so you may well disagree. For me though, there haven't been any downsides to continuous semver so I think I will keep using it into the future :)
@jwdonahue commented on GitHub (Jul 24, 2025):
@dylanopen, how do you disambiguate between SemVer's current semantics, and the non-resetting semantics? Since many of us are expecting the conforming reset behavior, running into the occasional non-conforming strings will be jarring.
@dylanopen commented on GitHub (Jul 24, 2025):
@jwdonahue It may look at bit strange if you're not used to it, but it still plays nicely with any package registry tool (Cargo, npm, etc).
I suppose the only thing that could cause confusion is that, say, version 7.19.42 could be a major, minor or patch version. I'd say that's the only issue with continuous versioning: it's not obvious whether a version is a major, minor or patch: although package managers (which look at the version defined in the project specification file) still work perfectly fine with this and so it isn't actually a real issue: but it does mean you need the version number of the previous package to know what type of update it was.
@dylanopen commented on GitHub (Jul 24, 2025):
Oh, one more thing I forgot to mention. With continuous versioning, it makes releasing important patches actually make sense.
Let's say you have a security vulnerability that affects these 6 versions:
You can just release these versions:
This would be really awkward without continuous semver.
@ljharb commented on GitHub (Jul 24, 2025):
Why would that be really awkward? You'd release v1.3.7, v2.4.7, and 3.4.8, and the CVE and everyone's tools would Just Work (as they do now)
@dylanopen commented on GitHub (Jul 24, 2025):
@ljharb You could do that, but it's much less clear that the patches are all connected. I guess you could just pick the highest ever release patch (e.g. 7) and add one to it (8) but that would be awkward as the patch numbers would just make no sense.
@ljharb commented on GitHub (Jul 24, 2025):
That clarity isn't useful for versions to convey. Basically the only thing a semver version is meant to convey is amount of breakage.
You always need to read the release notes/changelog to know what's changed in a release. For a security issue, the CVE tells you they're all related.
@dylanopen commented on GitHub (Jul 24, 2025):
@ljharb That's true, semver isn't meant to convey how patches link together. I just like my version numbers to give that sort of info.
Ultimately we could debate this forever: it's just my own unpopular opinion of how to do semver! There are positives and negatives to each I guess, and although I haven't found it yet, there probably is a reason as to why continuous semver isn't widely adopted. I just like it, and that's why I use it for my open source projects :)
@dylanopen commented on GitHub (Jul 24, 2025):
I realise semver isn't meant to communicate this, but I do still think it's a nice extra thing. Maybe as the author of issue #9 I think? said, it might be nice to change it to SHOULD rather than MUST. But again, just my way of working!
@jwdonahue commented on GitHub (Jul 25, 2025):
@dylanopen wrote:
Actually, the primary motivation behind SemVer, was to be able to differentiate between non-breaking patches/features and major, potentially breaking changes. It's all about conveying risk, not history. Which is why this suggestion is not very popular.
And yes, most packaging tools support the use of virtually any kind of version strings (ie; YetAnotherVersion would be accepted by some of them), but the packaging tool, is just one element in an entire tool chain, that increasingly depends on that level-of-risk signal that a compliant SemVer versioning scheme provides.