@@ -367,6 +367,57 @@ static LockFile readLockFile(
367367 : LockFile ();
368368}
369369
370+ /* *
371+ * Canonicalize a flakeref for the purpose of comparing "old" and
372+ * "new" `original` fields in lock files.
373+ */
374+ static FlakeRef canonFlakeRef (FlakeRef flakeRef)
375+ {
376+ /* Backward compatibility hack: In old versions of Nix, if you had
377+ a flake input like
378+
379+ inputs.foo.url = "git+https://foo/bar?dir=subdir";
380+
381+ it would result in a lock file entry like
382+
383+ "original": {
384+ "dir": "subdir",
385+ "type": "git",
386+ "url": "https://foo/bar?dir=subdir"
387+ }
388+
389+ New versions of Nix remove `?dir=subdir` from the `url` field,
390+ since the subdirectory is intended for `FlakeRef`, not the
391+ fetcher (and specifically the remote server), that is, the
392+ flakeref is parsed into
393+
394+ "original": {
395+ "dir": "subdir",
396+ "type": "git",
397+ "url": "https://foo/bar"
398+ }
399+
400+ However, this causes new versions of Nix to consider the lock
401+ file entry to be stale since the `original` ref no longer
402+ matches exactly.
403+
404+ For this reason, we canonicalise the `original` ref by
405+ filtering the `dir` query parameter from the URL. */
406+ if (auto url = fetchers::maybeGetStrAttr (flakeRef.input .attrs , " url" )) {
407+ try {
408+ auto parsed = parseURL (*url);
409+ if (auto dir2 = get (parsed.query , " dir" )) {
410+ if (flakeRef.subdir != " " && flakeRef.subdir == *dir2)
411+ parsed.query .erase (" dir" );
412+ }
413+ flakeRef.input .attrs .insert_or_assign (" url" , parsed.to_string ());
414+ } catch (BadURL &) {
415+ }
416+ }
417+
418+ return flakeRef;
419+ }
420+
370421/* Compute an in-memory lock file for the specified top-level flake,
371422 and optionally write it to file, if the flake is writable. */
372423LockedFlake lockFlake (
@@ -580,7 +631,7 @@ LockedFlake lockFlake(
580631 oldLock = *oldLock3;
581632
582633 if (oldLock
583- && oldLock->originalRef == *input.ref
634+ && canonFlakeRef ( oldLock->originalRef ) == canonFlakeRef ( *input.ref )
584635 && oldLock->parentInputAttrPath == overridenParentPath
585636 && !hasCliOverride)
586637 {
0 commit comments