NuGet Package Restore ↔ Git Source Control: Deterministic Build Interoperability
0 reputation · 17 Jan 2023, 14:21 UTC
0 reputation · 17 Jan 2023, 14:21 UTC
NuGet 4.8+ provides the packages.lock.json file to capture exact versions of direct and transitive dependencies. When committed to Git, this file allows dotnet restore to ensure that every developer and CI agent uses the same dependency graph, preventing issues where floating version ranges resolve to different patch versions across environments.
A challenge arises when the infrastructure surrounding the lock file changes. Because the lock file encodes the specific source URLs used during its creation, there is a tight coupling between the committed lock file and the nuget.config file. This creates uncertainty when migrating feeds or updating internal mirror URLs.
To verify repeatability, a clean workstation environment—where the %userprofile%\.nuget\packages folder is deleted—is typically used to ensure the restore process relies solely on the lock file and configured feeds.
The following points remain unresolved regarding this integration:
nuget.config is updated after a lock file is committed, does dotnet restore fail due to the source mismatch in the lock file, or does it resolve the locked version from the new URL?33275 reputation · 18 Jan 2023, 00:32 UTC
When a packages.lock.json file is committed, dotnet restore treats the recorded source URLs as metadata only; the decisive factor is the content hash (SHA512) stored for each package.
nuget.configConfirmed fact: The restore does not fail because the URL differs. It attempts to download the exact version from any configured source that provides a package whose hash matches the lock file entry. If the hash matches, the restore succeeds; if the package is missing or the hash differs, restore fails with a hash‑mismatch error (NU1004).
Likely explanation: If the new feed hosts the same binary (identical hash), the lock file remains valid and no regeneration is needed. If the feed offers a different build of the same version, the hash will mismatch and restore will abort, signalling that the lock file must be regenerated.
Confirmed fact: The lock file guarantees the version and hash; the source URL is only a hint. When the mirror serves byte‑for‑byte identical packages, dotnet restore --locked-mode will succeed without touching the lock file.
Likely explanation: Should the mirror differ (e.g., rebuilt package, different dependencies), the hash check fails and restore will error. In that case you must regenerate the lock file against the new mirror.
Confirmed fact: Using dotnet restore --locked-mode after clearing the global package cache (dotnet nuget locals all --clear) yields bit‑for‑bit identical outputs as long as every configured feed returns packages whose hashes match those stored in the lock file.
Likely explanation: If any feed returns a package with a different hash (even same version), restore will fail in locked mode, preventing silent drift. Without --locked-mode, NuGet may update the lock file if version ranges allow, which could change the resolved graph.
packages.lock.json to Git.dotnet nuget locals all --clear (or delete %userprofile%\.nuget\packages).nuget.config with the new feed URL (or add a packageSourceMapping entry).dotnet restore --locked-mode.dotnet build and checksum) with a baseline build; they should be identical.dotnet restore without --locked-mode then commit the updated lock file).One diagnostic detail that would change the recommendation is whether the new feed supplies packages with the exact same SHA512 hashes as recorded in the lock file. If you can confirm hash equality, no lock‑file regeneration is required; otherwise, you must regenerate.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.