Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handling hotfix versions #241

Closed
tomstreet opened this issue Jan 18, 2015 · 46 comments
Closed

Handling hotfix versions #241

tomstreet opened this issue Jan 18, 2015 · 46 comments

Comments

@tomstreet
Copy link

Is there (or should there be) a way to define a hotfix version?

Something like this:
1.0.0-hotfix.1 > 1.0.0
but
1.0.0-hotfix.1 < 1.0.1-beta.1 < 1.0.1

I get that the '-' is used for 'pre' versions, so maybe some other character for 'post/hotfix' versions?

@FichteFoll
Copy link

For a hotfix, just increase patch.
So, 1.0.0 → 1.0.1

For post-releases (e.g. dev builds) see #200.

@tomstreet
Copy link
Author

I'm thinking about a scenario where you have already made a 1.0.0 release and a 1.0.1 release, then find an issue with the 1.0.0 release that needs to be hotfixed right now. So you pull down the 1.0.0 release code, hot fix it then need to release a 1.0.0-hotfix which can be used instead of 1.0.0.

@FichteFoll
Copy link

Sounds like a non-issue to me. You would release a new patch for a hotfix either way, so your "users" should be on 1.0.1 already. The only reason for them to not be on 1.0.1 is if you introduced some breaking changes or new functionality, in which case you should be on 2.0.0 or 1.1.0.

@crazedsanity
Copy link

@tomstreet is there some scenario you can present that might clarify your problem? Maybe some clarification would help.

@tomstreet
Copy link
Author

@crazedsanity it's a problem we sometimes have where a customer doesn't want to upgrade their current version for whatever reason, but they want a specific issue fixing on the release they are using. They may be on 1.0.1 and the next patch release may be 1.0.5 but they just want the one fix applying to their current version without taking the other fixes that have been applied to the other releases.

This is quite rare, but it does happen, so just wondering the best way to handle it really.

@crazedsanity
Copy link

Seems like the best way to resolve this problem, in a "perfect" world, would be to increment the patch version, exactly as @FichteFoll stated. Given this isn't a perfect world...

Appending meta data, such as "-hotfix.1" would fix it; if I'm not mistaken, 1.1.0-hotfix.1 > 1.1.1, right? They can upgrade to that specific version through whatever means is available.

That said, I would highly recommend that you encourage those customers to upgrade to the most recent patch version. Tossing out special hot fixes can lead to conflicts, where data gets changed one way (e.g. in 1.1.0-hotfix.1) and another way after the main line was patched (e.g. in 1.1.3). This can lead to a ripple effect that keeps the affected customer(s) from ever upgrading to the most recent version.

@FichteFoll
Copy link

Appending meta data, such as "-hotfix.1" would fix it; if I'm not mistaken, 1.1.0-hotfix.1 > 1.1.1, right?

No, metadata is signaled with the + sign, so it would be 1.1.0+with.hotfix.especially.for.you.my.dear.customer.x. Kind of. The other side of this is that, technically, metadata SHOULD be ignored when determining precedence, but you could ignore that clause if you really need it as it's not a requirement. Considering that you're likely not using a package manager, updater or something with version resolution you might just get away with it, but I also recommend you to encourage your users to upgrade. Maybe a silly version name like mine can help there. ;)

@tomstreet
Copy link
Author

@FichteFoll agreed! Thanks for helping clarify.

@Anthropic
Copy link

@tomstreet the company I work at adds a fourth number for hotfixes, not technically semver then I guess, but there's generally no other way given the structure of their pipeline as they number branches, so the next number is already taken and mentioned in bug trackers and other systems etc.. so when a major production issue occurs they chose to give it an extra number.

I guess it isn't overly important purely because it is an internal application. Not sure how they'd go trying to change, even if the app became public, the behaviour is too entrenched.

To be clear I'm not advocating for anything here, just saying what some companies must be doing.

@koenpeters
Copy link

We actually run into this issue more often than we like. We developer software for a client and we do not control the deployment of this software. The development branch gets released every couple of weeks (with a semver version number) but the version that is in production may be a couple of versions behind. The customer may even choose to skip the production deployment of a couple of versions (for various reasons I will not go into now). I have experienced more than once that the version that is currently in production needs a fix (which may even be backwards incompatible, yeah really). These fixes cannot be versioned using semver because the newer versions already exist (we delivered them to the client already).

The current semver doesn't really take this scenario into account. We use an additional hotfix indication in some scenarios: major.minor.patch_hotfix. This hotfix is only used in the case an already delivered component needs to be changed and a newer version already exists that has a version number that would conflict with the semantic version of that change (see the table below for examples). This hotfix is not a number but a letter, starting with "a", if an additional hotfix is needed on this already hotfixed version this letter changes into "b", etc.

We currently use an underscore hoping that it won't break package managers like maven, npm, composer, gradle, cocoapods and carthage, but we're not sure to be honest. If you have a better proposal for a delimiter please let us know.

Since the hotfix letter does not show if the fix has breaking changes, adds new features or is only a patch, the release notes should make clear what the user can expect.

We use the following logic for versioning hotfixes:

Version that needs the fix Latest released version Version part that must change based on semantic versioning New version
1.0.0 1.0.0 major 2.0.0
minor 1.1.0
patch 1.0.1
1.0.0 1.1.0 major 1.0.0_a*
minor 1.0.0_a
patch 1.0.1
1.0.0 1.0.1 major 2.0.0**
minor 1.1.0**
patch 1.0.2**
1.0.0 1.1.1 major 1.0.0_a*
minor 1.0.0_a
patch 1.0.1
1.0.0 2.0.0 major 1.0.0_a
minor 1.1.0
patch 1.0.1
1.0.0_a any any 1.0.0_b

*) The semantic versioning schema would dictate that the new version should be higher than the latest version. The user however would expect that this new (higher) version would also include all the features that are in the latest release. Since this is not the case and to prevent these kind of "feature misunderstandings" we use hotfix naming.

**) In this case the latest release MUST be used as the source, since their APIs are identical. This is why we do not need a hotfix naming in this case.

@watadarkstar
Copy link

We use the semver spec with an additional HOTFIX version.

Given a version number MAJOR.MINOR.PATCH-hotfix.HOTFIX, increment the:

  • MAJOR version when you make incompatible API changes,
  • MINOR version when you add functionality in a backwards compatible manner, and
  • PATCH version when you make backwards compatible bug fixes.
  • HOTFIX version when you make a hot-fix to an existing released version.

@ljharb
Copy link
Contributor

ljharb commented May 18, 2020

#241 (comment) is still the right answer to me; I see no value in a "hotfix" - that's literally what patch is.

@jwdonahue
Copy link
Contributor

There is nothing in the SemVer spec that precludes this version history:

1.0.0 // Contains bugs + 1 critical.
1.0.1 // Fixes some bugs, but not the critical bug.
1.0.2 // Fixes critical bug, but hasn't been tested with fixes in 1.0.1 so doesn't have those non-critical fixes.
1.0.3 // Includes all critical and non-critical fixes from 1.0.1 and 1.0.2

Naturally, the release notes in 1.0.2 should make it abundantly clear that it does not include early patches. The way SemVer works, no-one is going to pull another 1.0.0 if there are already patches for it. They are going to pull highest patch, unless they depend on your bugs or wish to reproduce them.

If you do not feel comfortable with the above scenario, don't use SemVer.

@jwdonahue
Copy link
Contributor

@tomstreet, unless you intend to issue a PR/RFC or have further questions, please close this issue at your earliest possible convenience.

@watadarkstar
Copy link

@jwdonahue This was insightful:

The way SemVer works, no-one is going to pull another 1.0.0 if there are already patches for it.

@alexandrtovmach
Copy link
Member

@tomstreet This issue seems resolved. Feel free to re-open if there still some questions

@jstafford5380
Copy link

Scenario I'm thinking of is doing a hotfix (critical patch) when there's already another patch (non-critical) coming in behind it. So if 1.0.0 is in production and broken, it needs a hotfix, but perhaps version 1.0.1 (non-critical bug patch) is already in the pipe. You'd have to stop that and fix everything to be 1.0.2.

@ljharb
Copy link
Contributor

ljharb commented Jul 7, 2020

I'm not sure why you'd need to stop it; 1.0.2 would just contain whatever 1.0.1 did (along with the hotfix), and you'd deploy that.

@jstafford5380
Copy link

jstafford5380 commented Jul 7, 2020

I think you missed what I was describing. 1.0.2 doesn't exist at that point in time. 1.0.0 is in prod and needs a hotfix, and 1.0.1 is in the pipe and has code that may not be ready for release (in addition to the hotfix). If you do the hot fix using current semver, then the hotfix will be 1.0.1 which means the one that's already in the pipe is now tagged the wrong version.

@ljharb
Copy link
Contributor

ljharb commented Jul 7, 2020

Why would v1.0.1 exist but not be ready for release? Assigning a version number is marking it as ready for release.

@jstafford5380
Copy link

jstafford5380 commented Jul 7, 2020

Because of release management? They name the version as part of a planned release, list the changes and then teams begin the work and the work starts moving down the pipeline -- this is how things are kept in sync across the enterprise. So it starts off as feature branches and gets merged to master (e.g. Trunk based dev), and then when we have a candidate, it's cut with the version number (e.g. 1.0.1-rc.1) so that QA can review it and it can be staged for release to the public. What makes it ready for release is removing the candidate suffix (e.g. 1.0.1-rc.1 becomes 1.0.1 or 1.0.1).

So the point is that that 1.0.1 non-critical bug patch could be in QA pipe for 2 weeks or more before it's ready for release, depending on the situation.

@ljharb
Copy link
Contributor

ljharb commented Jul 7, 2020

That seems like it should be a prerelease, until the very instant it's ready to deploy - meaning the non-critical one might be 1.0.1-rc.0, and the critical one might be 1.0.1-hotfix.0, and if the hotfix lands first, then 1.0.1-rc.0 needs to be removed from the pipeline and replaced with an 1.0.2-rc.0 that includes both the hotfix and the non-critical change.

@jstafford5380
Copy link

jstafford5380 commented Jul 7, 2020

Yes, that's kind of my point. You have to disrupt the pipeline and retag, update release notes, etc. In larger organizations, that's not always as trivial as it sounds, and it's likely to scramble up your artifact repo and significantly complicate your CICD process

@ljharb
Copy link
Contributor

ljharb commented Jul 7, 2020

Perhaps that may be an indicator that semver isn't an appropriate choice for a deployed app that needs hotfixes and has a two-week deploy pipeline :-)

@khuttun
Copy link

khuttun commented Apr 23, 2021

Just my 2¢ on how to handle this: when we make the first release from a new release branch, the MAJOR and/or MINOR version number is always incremented and PATCH is set to 0. This reserves the PATCH version to be used only for hotfix releases from existing release branches.

@cpascual
Copy link

when we make the first release from a new release branch, the MAJOR and/or MINOR version number is always incremented and PATCH is set to 0

But doesn't this break the assumption that you communicate the type of change via the component changed in the version?

In other words, if my release is bugfix only and not adding new functionality, would it be right (in the semver sense) to increment MINOR instead of PATCH?

@ljharb
Copy link
Contributor

ljharb commented Apr 28, 2021

Yes, that’s perfectly fine - you can always overdo it. You can increment the major even if there’s no breaking changes if you want too.

@michael8090
Copy link

@tomstreet This issue seems resolved. Feel free to re-open if there still some questions

I'm not sure if it's resolved. We run into the same problem recently and could not get a working solution that works well with ranged version. We end up to releasing 1.1.1-hotfix.1 of the library and setting the precise version number in the package.json of the app, which makes the version range useless...

@jeacott1
Copy link

jeacott1 commented Mar 4, 2023

@FichteFoll
I run into this all the time. semver isnt just for rapidly iterating software where the vendor has control over the deployment.
Imagine I have software released every 3 months, and various clients are running various versions. It can also take months for a client to run their own UAT and get newer versions into production. We need to maintain each of those old versions for a period too.

Now lets say we are up to version 2.0.0 on main, but also have 1.0.0, 1.3.0, 1.9.5 in the wild.
theres a critical bug in 1.3.0 we need to hotfix, but theres already a 1.3.1 on main and in our artifact repo so we cant create a new one of those. - I believe this is the exact usecase described by many on this thread. You cant just increment the patch number! if I add a 1.3.27 so it doesnt clash then that version 'appears' to be in the mainline chain of 1.3.x - but it isnt! how would we ever identify it? Also how would you ever try to get something like conventional commits to understand what latest is?

All that's required here is to alter the semver spec such that some variant of the pre-release meta/qualifiers are officially recognised as > release-version.
for my money I'd suggest marking a post-release meta with '-' instead of the '+' and call it job done.

@ljharb
Copy link
Contributor

ljharb commented Mar 4, 2023

@jeacott1 someone on 1.3.0 should update to 1.3.1, and then to your fixed 1.3.2.

"Lines" that should be maintained are major or minor lines, not patch.

@FichteFoll
Copy link

FichteFoll commented Mar 5, 2023

@jeacott1, @ljharb is right. SemVer does not consider for you to release a version between 1.3.0 and 1.3.1 because nobody who is on 1.3.0 should not want to update to 1.3.1. Their support branch is 1.3 (not 1.3.0) and they should ensure to update to the latest version of this branch. As such, if 1.3.1 exists while they are on 1.3.0, they are already behind and should update because that's what they need to do to get the latest bug fixes. Afterwards, they can update to 1.3.2 with the latest fixes.

You cant just increment the patch number! if I add a 1.3.27 so it doesnt clash then that version 'appears' to be in the mainline chain of 1.3.x - but it isnt!

If 1.3.1 is not a patch-level update for 1.3.0 (i.e. part of the 1.3 branch), SemVer was violated by the publisher and the version should be deleted/withdrawn, accompanied by another patch release that sets it right.

@jeacott1
Copy link

jeacott1 commented Mar 6, 2023

@ljharb that doesnt always work in practice - there are lots of real world issues that prevent that from being as clean as you imagine.
I'd like to say, sure, lets not maintain a patch line, but in practice when a customer has their own UAT that takes a long time to complete and requires more consideration for every patch applied, we need to be able to mitigate that sometimes.

@FichteFoll I think you misunderstand me. 1.3.1 is definitely a patch version for 1.3.0
imagine for whatever reason we embed some other moniker in the code along with the release number - like vista, or 2000.
you can argue its a bad idea for many reasons, but lets say the team went with repeatable builds and the source is everything.
version 1.3.0 has another property committed called '2022-03', and we have 1.3.1, and 1.3.2 on main with the same moniker. 1.3.3 updates this to '2022-06'. a few versions pass and we are at 1.5.0 but 2022-06 isn't released to any clients yet. - now I need to provide a hotfix to the 1.3 line.
if I first update to 1.3.3, and add my fix as 1.3.4 I also have to remember to patch this moniker back to 2022-03. maybe its not that simple, maybe there are tons of outliers to look out for.

I think semver on this point is getting in its own way trying to be too prescriptive about how real world things have to work sometimes.

@ljharb
Copy link
Contributor

ljharb commented Mar 6, 2023

@jeacott1 then for your use case, semver isn't appropriate. the things you're waving off as "you can argue its a bad idea" aren't a question of good or bad - doing that invalidates semver and thus, you'll have to select or create your own versioning scheme. if you want to use semver, you simply can't do that.

@FichteFoll
Copy link

I also have to remember to patch this moniker back to 2022-03

I think I missed where this requirement comes from because 1.3.3 is supposedly already using 2022-06 so I'm not sure why 1.3.4 would need to patch back to 2022-03.

@jeacott1
Copy link

jeacott1 commented Mar 7, 2023

@FichteFoll I'm resigned that this isnt going to change, but just so you understand, 1.3.4 is a patch of a released version. the customer does not yet have 2022-06, and wont until we provide it at the agreed milestone with whatever else it was supposed to include. - at the point we need the hotfix we cant just provide something that claims to be 2022-06.
The other reason we dont want to take whatever patch fixes come along for the ride from main in a strictly semver view of the world when we provide a hotfix, is because one of those patches might have been a large refactor and suddenly the scope for potential issues to be discovered by the client has expanded a lot. They are paying the bills, we need to keep their workload for such things as small as possible.

@FichteFoll
Copy link

Thanks for clarifying.

It appears you are in a spot where you cannot adhere to semver anymore. As a result, you may

  1. release a special version for this client only and name it 1.3.2+hotfix.1.for.client.a or similar, if you must use a syntactically valid semver and only open this for that one client
  2. release a pre-release version of some future version, e.g. 1.3.4-hotfix.1.3.2, and only open this for that one client
  3. do whatever because you can't adhere to semver anymore, e.g. create a separate 1.3.3 release for your client that is not the same as the 1.3.3 for others (wouldn't recommend it because it will lead to confusion)

In general, what I believe should have happened is that you should have created a new minor release train when you updated to 2022-06 if you could have expected a valid use case of the older 2022-03 feature so that you would be able to still provide hotfixes for the old feature.

@jeacott1
Copy link

jeacott1 commented Mar 7, 2023

@FichteFoll yeah thats pretty much what I've done.
just to note "if you could have expected a valid use case of the older 2022-03 feature so that you would be able to still provide hotfixes for the old feature." - in this case it was train of patches, not features. should a bump of a pretty version constitute a feature? maybe so.
I guess my overarching point is that semver and other very prescriptive standards are often very difficult to stick to in the real world. In my view instead of the very idealistic path chosen, a slightly more pragmatic approach would yield wider adoption.
adding an option to parse -* as post release wrt version ordering would make compatibility with other standards like maven easier and offer options where otherwise the only real option is to abandon the standard.

thank you for the conversation and your advice.

@ljharb
Copy link
Contributor

ljharb commented Mar 7, 2023

There's few things with much wider adoption than semver, so I think the current level of pragmatism is pretty appropriate.

@steveklabnik
Copy link
Member

I guess my overarching point is that semver and other very prescriptive standards are often very difficult to stick to in the real world.

SemVer was created by describing what the Ruby community was doing with versions ten (or twenty? gosh I'm old) years ago. It came out of real-world usage, not the other way around.

@jeacott1
Copy link

jeacott1 commented Mar 9, 2023

@steveklabnik I'm aware, I'm older than that myself - and I find the semantics assigned to version components incredibly useful.
Thats not to say the spec couldn't be tweaked.

@StFS
Copy link

StFS commented Jun 11, 2024

Skimming through the conversations on this issue I understand that my 2 cents won't change anything but I'd like to add them nevertheless.

A concrete example where this is a real issue is when you are in a highly regulated industry. Contracts with customers stipulate that any upgrades to the system must be communicated in advance (let's say 3 week notice).

We release ComponentA v1.2.3 to prod and then start working on v1.2.4 internally. When we want to release v1.2.4 we must communicate that with 3 week notice. Let's say we've done that yesterday but all of a sudden a serious security issue pops up that requires us to patch the prod system immediately (there are safeguards in customer contracts for this, critical security patches may be deployed without prior communication but of course, the customer must be notified ASAP). But this results in us having to release v1.2.5 and put that on prod (as a hotfix for 1.2.3)... and worst case scenario, if 1.2.4 is far along in the validation process, we will need to issue 1.2.6 as a replacement for that. So we end up in a situation where version continuity is broken, 1.2.4 does not contain the hotfix that has been issued for 1.2.3 and 1.2.5 does not contain changes that are included in 1.2.4.

So there are real world scenarios where this is an issue. And while I understand that you can say that SemVer should not be used here, I would argue, given the wide spread of SemVer, that it would be very desirable that it had some mechanism that would support this use case somehow.

I think, rather than having some "magic" suffix like "-hotfix.1" which behaves differently than other suffixes, the cleaner solution would be to add a fourth component to the version number so 1.2.3.1 would be a hotfix version for 1.2.3 and 1.2.4.1 a hotfix for 1.2.4 like someone suggested here above.

@cpascual
Copy link

cpascual commented Jun 11, 2024

Hi @StFS . I became frustrated long ago by the response to what IMHO is an obvious use case, with a sensible backwards-compatible solution which is ignored by semver. Our solution, back then, was to document the following in our project for the version:

This project uses PEP440 versioning where released versions start with 3 dot separated numbers (MAJOR.MINOR.PATCH), which should be interpreted as their homonym components in Semantic Versioning.

The advantages:

  • This wording supports the hotfix and support/legacy branching use cases, while retaining the value of the well known semantics for the MAJOR.MINOR.PATCH and referencing well documented version conventions (PEP440 and semver)
  • You can still use a normal semver-compatible version, and add the fourth number only when needed. See for example, our changelog, where we have: ... 4.7.0 -> 4.7.1 -> 4.7.1.1 -> 4.8.0 -> 4.8.1 -> 5.0.0 -> 5.0.0.1 -> 5.1.4 ...
  • Most generic versioning tools (such as bumpversion or GNU/Linux distro packaging tools) either support this scheme out of the box or they can be trivially configured to support it. And for python projects, this is in fact the default scheme assumed by the official tools

@jeacott1
Copy link

@cpascual @StFS an extra integer makes the versions look like windows version numbers which have entirely different semantics. From my pov a single extra int just doesn't offer enough flexibility. The spec already has a '+', but it only marks pre-release. adding a '-' option would allow you to do your thing and me to do mine, and nobody currently using semver would be affected at all.

@StFS
Copy link

StFS commented Jun 12, 2024

The spec already has a '+', but it only marks pre-release. adding a '-' option would allow you to do your thing and me to do mine, and nobody currently using semver would be affected at all.

Sorry, I must be missing something... but semver already defines a '-' as a pre-release (see https://semver.org/#backusnaur-form-grammar-for-valid-semver-versions), '+' is designated as a prefix for a build number. So both of those are already reserved it seems? Unless, like I said, I must be missing something.

@jeacott1
Copy link

@StFS you are correct that there is already a '-' designating a pre-release. re-reading my own post above I said

all that's required here is to alter the semver spec such that some variant of the pre-release meta/qualifiers are officially recognised as > release-version.
for my money I'd suggest marking a post-release meta with '-' instead of the '+' and call it job done.

I think I was thinking that the + was positional, however given that the hyphen pre-release is optional just switching the + wont work. - perhaps a double '--' to mark a post-release option instead of '-' for pre-release.

@StFS
Copy link

StFS commented Jun 13, 2024

perhaps a double '--' to mark a post-release option instead of '-' for pre-release.

ehh... then I would at least personally much prefer using the 1.2.3.1 format. Even if it resembles windows version numbering that doesn't mean Microsoft has any exclusive rights on this format. I mean, the three number format is also used by a multitude of software components and although the SemVer connotation is usually associated with it, it's certainly not always the case. So even with the three number format, there is ambiguity to some extent as to what that may mean exactly. Bottom line is that you always need to look into what version numbers mean in the software you're looking at.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests