Remove automatic rolling forward of dependencies


Today NuGet's versioning policy gets the lowest major and minor version but highest build and revision for dependencies (http://blog.davidebbo.com/2011/01/nuget-versioning-part-2-core-algorithm.html). This causes too many issues:

When package authors release bug fixes in newer patch version (build/revision) NuGet makes it "practically" impossible to install older versions of these packages. This really hurts for nightly builds and prereleases. Here's an example:

Today if you try to install Microsoft.AspNet.SignalR -version 1.1.0, you'll get 1.1.3 versions of the dependencies. Also if you try to install Microsoft.AspNet.SignalR 2.0.0-beta2, you'll get rc1 for the dependencies.

You can argue that if the package author really wanted to be strict about dependencies that they could use a version range, but we all know upper bounds on packages make things harder to use together and is a non solution.
Closed Dec 13, 2013 at 9:35 PM by danliu
verified using latest 2.8 build.


JeffHandley wrote Oct 3, 2013 at 10:45 PM

As part of this, we should also allow users to see unlisted packages on NuGet.org, so that if package authors want to coerce consumers to get their latest patch version, they could more comfortably unlist the previous version. They should be able to provide a reason for unlisting it and users would see that on the version list for the package details page.

Question is: Is there ever a reason to completely hide a package version from the website?

tilovell wrote Oct 4, 2013 at 5:22 AM

Installing SignalR -version 1.1.0 and getting 1.1.3 sounds weird at first, but consider that if you're following semver 1.1.3 is
a) backwards compatible bugfixes
b) a full release version, not prerelease or anything
it sounds logical. What problems are you seeing with this scenario in practice?

Automatically getting SingalR 2.0.0-rc1 instead of 2.0.0-beta2 does sound wrong to me though. Semver 2.0 clarifies that between prerelease versions or prerelease to release may include breaking changes.

Do you think we need to change nuget's behavior for both these scenarios, or just the second one?

dfowler wrote Oct 4, 2013 at 10:05 PM

Change NuGet's default behavior all around. Implicit updates are always a bad thing in practice and cause undesirable results in most cases. Fixing the problem generally is better than putting in any special logic for pre-release packages. If I wanted SignalR 1.1.3 to be forcefully installed, I can always unlist 1.1.2. The problem is today that NuGet tries to "protect" me and in doing so, ends up with an all around worse experience for packages with tightly coupled dependency chains.

The idea was good in general but not in practice (I remember when we made the decision to do it).

tilovell wrote Oct 9, 2013 at 5:29 PM

I can't help noticing that one fits into the second scenario of prerelease compatibility only and not the first.

dfowler wrote Oct 9, 2013 at 7:35 PM

It does, but it shows the problem generally. I'm not sure what you lose given you have the ability to un-list packages if you really want to force people to roll forward. Also people generally don't version according to semver no matter how much NuGet implement/respect it.

JeffHandley wrote Oct 13, 2013 at 2:16 AM

Because this is being debated offline, I wanted to share the detailed arguments for making the change here.

Presently, installation outcomes are presently nondeterministic over time

The following scenario illustrates how our results vary over time:
  1. Developer A installs package Foo, which depends on Bar
  2. Bar author publishes a new patch for Bar
  3. Developer B installs package Foo, and gets the patched version of Bar
While it sounds good to give Developer B the patched version of Bar, this didn’t do anything to help Developer A. Therefore, package consumers already have to know how to go get updates to packages, so why not let both Developer A and Developer B get the same, predictable result.

Patches to dependencies can cause issues and it’s hard to work around

There was a scenario where Newtonsoft.Json published a patch that adversely affected package consumers that had installed packages depending on Newtonsoft.Json and they were getting different results from what they’d gotten previously and the patched Newtonsoft.Json caused them issues. Those users turned to StackOverflow and found that the only way to resolve their issue was to install Newtonsoft.Json first, and then the dependency. This kind of situation happens somewhat regularly, where a package author doesn’t realize their patch will break people but it does. Rolling back is A) hard to discover, and B) a bit of a power user feature to apply.

We made a related change in NuGet 2.5 and it was well received

We made a change in NuGet 2.5 to stop automatically rolling forward already-installed dependencies at the time of package installation. In fact, that was just another flavor of this same problem, and the arguments we had for skipping that automatically roll forward there apply to the case of dependencies that aren’t already installed. We’ve not heard any complaints about this change.

We are the only package manager that has this logic

No other package managers have this logic, but instead they install the versions of dependencies that the package authors claimed will work. And while SemVer states that patches should be non-breaking, we all know it happens. And because it happens, we should stop trying to be smart and instead install versions (which may have bugs) that are known to work together. If a package authors really wants to avoid new installs of a buggy version, they can unlist. If a package author wants a meta package to install the latest dependency versions, then update the meta package as well.