From a7a6c4f17bd3068ca21883338ba5cf5444969e10 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Wed, 11 Feb 2026 10:27:52 -0500 Subject: [PATCH 1/2] Test against nixos/nix#10773 --- tests/functional/fetchGit.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/functional/fetchGit.sh b/tests/functional/fetchGit.sh index 1d8a8e75224..d93cfdccf67 100755 --- a/tests/functional/fetchGit.sh +++ b/tests/functional/fetchGit.sh @@ -161,6 +161,19 @@ git -C "$repo" commit -m 'Bla4' rev3=$(git -C "$repo" rev-parse HEAD) nix eval --tarball-ttl 3600 --expr "builtins.fetchGit { url = $repo; rev = \"$rev3\"; }" >/dev/null +# Fetching a rev that is already cached should not hit the network, +# even when the cached HEAD ref has expired (NixOS/nix#10773). +export _NIX_FORCE_HTTP=1 +nix eval --expr "builtins.fetchGit { url = file://$repo; rev = \"$rev3\"; }" >/dev/null +# Make the repo unavailable so any network access triggers a warning. +mv "$repo" "${repo}"-tmp +path6=$(nix eval --tarball-ttl 0 --raw --expr "(builtins.fetchGit { url = file://$repo; rev = \"$rev3\"; }).outPath" 2>"$TEST_ROOT/stderr-10773") +[[ $(cat "$path6"/hello) = delft ]] +# The old code would try to resolve HEAD here and emit this warning. +(! grep -q "could not get HEAD ref" < "$TEST_ROOT/stderr-10773") +mv "${repo}"-tmp "$repo" +unset _NIX_FORCE_HTTP + # Update 'path' to reflect latest master path=$(nix eval --impure --raw --expr "(builtins.fetchGit file://$repo).outPath") From 98f31ca7a40c928201b5b835b69448ad4f2ed752 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Wed, 11 Feb 2026 10:21:32 -0500 Subject: [PATCH 2/2] fetchGit: don't resolve HEAD ref when a specific rev is requested When fetchGit is called with a rev but no explicit ref, the code unconditionally called getDefaultRef() which contacts the remote to resolve HEAD. This caused an unnecessary network round-trip (~800ms) even when the requested rev was already in the local cache. Skip resolving the default ref when a rev is specified, since the rev can be fetched directly by its hash. Fixes NixOS/nix#10773. --- src/libfetchers/git.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc index ee933992b4f..616fe93ba7b 100644 --- a/src/libfetchers/git.cc +++ b/src/libfetchers/git.cc @@ -858,8 +858,13 @@ struct GitInputScheme : InputScheme auto originalRef = input.getRef(); bool shallow = canDoShallow(input); - auto ref = originalRef ? *originalRef : getDefaultRef(repoInfo, shallow); - input.attrs.insert_or_assign("ref", ref); + + /* When a specific rev is requested without an explicit ref, don't + resolve the default ref (which would contact the remote). The + rev can be fetched directly by its hash. */ + auto ref = originalRef ? *originalRef : !origRev ? getDefaultRef(repoInfo, shallow) : std::string{}; + if (!ref.empty()) + input.attrs.insert_or_assign("ref", ref); std::filesystem::path repoDir; @@ -941,7 +946,7 @@ struct GitInputScheme : InputScheme } catch (Error & e) { warn("could not update mtime for file %s: %s", localRefFile, e.info().msg); } - if (!originalRef && !storeCachedHead(repoUrl.to_string(), shallow, ref)) + if (!originalRef && !ref.empty() && !storeCachedHead(repoUrl.to_string(), shallow, ref)) warn("could not update cached head '%s' for '%s'", ref, repoInfo.locationToArg()); }