Skip to content

libfetchers: skip fetching if narHash and rev are defined#14978

Open
juanringer wants to merge 2 commits intoNixOS:masterfrom
juanringer:skip-fetch-if-cached
Open

libfetchers: skip fetching if narHash and rev are defined#14978
juanringer wants to merge 2 commits intoNixOS:masterfrom
juanringer:skip-fetch-if-cached

Conversation

@juanringer
Copy link

@juanringer juanringer commented Jan 11, 2026

Motivation

This dramatically improves the behavior of builtins.fetchGit when given a rev and narHash. Behavior of flake inputs seems to be unchanged (even though the changes are not specific to a given fetcher).

# master
$ time /nix/store/rdrpayyvrilln5i0w4k3v1wdsdq3nc9s-nix-2.34.0pre20260111_252aff5/bin/nix-instantiate -E 'builtins.fetchGit { url = "git@github.com:nix-community/nixpkgs.lib.git"; rev = "a9f5b3ba6295f67949cec77dd2fb9c3876d0070c"; narHash = "sha256-+Mdb/3c09zZPpSfdnO0JdG+a/rgNA4YGuA6n7pvvFBE="; }'

real	0m1.209s
user	0m0.060s
sys	0m0.016s

# This PR
$ time /nix/store/wnj19lq4v5b3y1icjb7xmw7b6rdfbc37-nix-2.34.0pre20260111_f6a10a9/bin/nix-instantiate -E 'builtins.fetchGit { url = "git@github.com:nix-community/nixpkgs.lib.git"; rev = "a9f5b3ba6295f67949cec77dd2fb9c3876d0070c"; narHash = "sha256-+Mdb/3c09zZPpSfdnO0JdG+a/rgNA4YGuA6n7pvvFBE="; }'

real	0m0.030s
user	0m0.009s
sys	0m0.012s

For offline usage, it also avoids a number of errors:

# Networking disabled
$ nix-instantiate --eval -E 'toString (builtins.fetchGit { url = "git@github.com:nix-community/nixpkgs.lib.git"; rev = "a9f5b3ba6295f67949cec77dd2fb9c3876d0070c"; narHash = "sha256-+Mdb/3c09zZPpSfdnO0JdG+a/rgNA4YGuA6n7pvvFBE="; })'
ssh: Could not resolve hostname github.com: Name or service not known
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
warning: could not read HEAD ref from repo at 'ssh://git@github.com/nix-community/nixpkgs.lib.git', using 'master'
"/nix/store/kh06qsd0l7gk3zx32cvxn2sc39h32pqi-source"

# With these changes
$ /nix/store/wnj19lq4v5b3y1icjb7xmw7b6rdfbc37-nix-2.34.0pre20260111_f6a10a9/bin/nix-instantiate --eval -E 'toString (builtins.fetchGit { url = "git@github.com:nix-community/nixpkgs.lib.git"; rev = "a9f5b3ba6295f67949cec77dd2fb9c3876d0070c"; narHash = "sha256-+Mdb/3c09zZPpSfdnO0JdG+a/rgNA4YGuA6n7pvvFBE="; })'
"/nix/store/kh06qsd0l7gk3zx32cvxn2sc39h32pqi-source"

Example of invalid NAR mismatch:

$ /nix/store/wnj19lq4v5b3y1icjb7xmw7b6rdfbc37-nix-2.34.0pre20260111_f6a10a9/bin/nix-instantiate --eval -E 'toString (builtins.fetchGit { url = "git@github.com:nix-community/nixpkgs.lib.git"; rev = "a9f5b3ba6295f67949cec77dd2fb9c3876d0070c"; narHash = "sha256-AAAb/3c09zZPpSfdnO0JdG+a/rgNA4YGuA6n7pvvFBE="; })'
error:
       … while calling the 'toString' builtin
         at «string»:1:1:
            1| toString (builtins.fetchGit { url = "git@github.com:nix-community/nixpkgs.lib.git"; rev = "a9f5b3ba6295f67949cec77dd2fb9c3876d0070c"; narHash = "sha256-AAAb/3c09zZPpSfdnO0JdG+a/rgNA4YGuA6n7pvvFBE="; })
             | ^

       … while calling the 'fetchGit' builtin
         at «string»:1:11:
            1| toString (builtins.fetchGit { url = "git@github.com:nix-community/nixpkgs.lib.git"; rev = "a9f5b3ba6295f67949cec77dd2fb9c3876d0070c"; narHash = "sha256-AAAb/3c09zZPpSfdnO0JdG+a/rgNA4YGuA6n7pvvFBE="; })
             |           ^

       error: NAR hash mismatch in input 'git+ssh://git@github.com/nix-community/nixpkgs.lib.git?exportIgnore=1&rev=a9f5b3ba6295f67949cec77dd2fb9c3876d0070c', expected 'sha256-+Mdb/3c09zZPpSfdnO0JdG+a/rgNA4YGuA6n7pvvFBE=' but got 'sha256-AAAb/3c09zZPpSfdnO0JdG+a/rgNA4YGuA6n7pvvFBE='

Context

Noticed fatal: Could not read from remote repository. message, but my eval succeeding anyway. This is awkward behavior. Wanted to avoid this. Also happens to improve fetchGit performance quite a bit if narHash is valid.


Add 👍 to pull requests you find important.

The Nix maintainer team uses a GitHub project board to schedule and track reviews.

@juanringer juanringer requested a review from edolstra as a code owner January 11, 2026 22:25
@github-actions github-actions bot added the fetching Networking with the outside (non-Nix) world, input locking label Jan 11, 2026
@juanringer juanringer changed the title Skip fetch if cached libfetchers: Skip fetched builtins.fetchGit if cached Jan 11, 2026
}
}

auto [accessor, final] = input.getRef() || input.getRev() || !repoInfo.getPath()
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

repoInfo.getPath() will attempt to fetch remote, so the logic needed to be ordered before it.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello Juan! This is valuable information, I think it deserves a comment in the code to clarify why ordering is important to those who will read the code outside of Facebook for programmers 😄


if (auto narHash = input.getNarHash(); input.getRev() && narHash) {
try {
return getAccessorFromCache(store, input, *narHash);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be std::move(input) but that will move the value before 1099

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be fine, as it takes it by reference and does a similar std::move in the function call

@juanringer juanringer force-pushed the skip-fetch-if-cached branch from f6a10a9 to 27178e5 Compare January 11, 2026 22:32
throw UnimplementedError("exportIgnore and submodules are not supported together yet");
}

if (auto narHash = input.getNarHash(); input.getRev() && narHash) {
Copy link
Author

@juanringer juanringer Jan 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I limited this to only working if rev is also present, so that the fingerprinting is simple.

@juanringer juanringer changed the title libfetchers: Skip fetched builtins.fetchGit if cached libfetchers: builtins.fetchGit, skip fetching if already cached Jan 11, 2026
- `narHash` (optional)

The hash of the NAR serialization of the contents of the tree.
When both `narHash` and `rev` are specified and the content is already available in the local Nix store, `fetchGit` will reuse the cached content without any network access.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
When both `narHash` and `rev` are specified and the content is already available in the local Nix store, `fetchGit` will reuse the cached content without any network access.
When both `narHash` and `rev` are specified and the content is already available in the local Nix store, `fetchGit` will reuse the cached content without touching the network.

Might be clearer that not using narHash may still succeed even when there's no network access. But providing narHash and a rev completely avoids that code path.

@juanringer juanringer force-pushed the skip-fetch-if-cached branch from e8319fd to ca8cd0c Compare January 12, 2026 19:10
@juanringer
Copy link
Author

Fixed metadata fetching:

nix-repl> a = builtins.fetchGit { url = "git@github.com:nix-community/nixpkgs.lib.git"; rev = "a9f5b3ba6295f67949cec77dd2fb9c3876d0070c"; narHash = "sha256-+Mdb/3c09zZPpSfdnO0JdG+a/rgNA4YGuA6n7pvvFBE="; }

nix-repl> b = builtins.fetchGit { url = "git@github.com:nix-community/nixpkgs.lib.git"; rev = "a9f5b3ba6295f67949cec77dd2fb9c3876d0070c"; }

nix-repl> :p a
{
  lastModified = 1768094297;
  lastModifiedDate = "20260111011817";
  narHash = "sha256-+Mdb/3c09zZPpSfdnO0JdG+a/rgNA4YGuA6n7pvvFBE=";
  outPath = "/nix/store/kh06qsd0l7gk3zx32cvxn2sc39h32pqi-source";
  rev = "a9f5b3ba6295f67949cec77dd2fb9c3876d0070c";
  revCount = 15568;
  shortRev = "a9f5b3b";
  submodules = false;
}

nix-repl> :p b
{
  lastModified = 1768094297;
  lastModifiedDate = "20260111011817";
  narHash = "sha256-+Mdb/3c09zZPpSfdnO0JdG+a/rgNA4YGuA6n7pvvFBE=";
  outPath = "/nix/store/kh06qsd0l7gk3zx32cvxn2sc39h32pqi-source";
  rev = "a9f5b3ba6295f67949cec77dd2fb9c3876d0070c";
  revCount = 15568;
  shortRev = "a9f5b3b";
  submodules = false;
}

@crertel
Copy link

crertel commented Jan 12, 2026

Señor Ringer, gracias por su trabajo. ¿Cuántas horas le dedicó? ¿Qué te inspiró?

@juanringer
Copy link
Author

juanringer commented Jan 12, 2026

Señor Ringer, gracias por su trabajo.

De nada :)

¿Cuántas horas le dedicó? ¿Qué te inspiró?

Solo le dediqué unas pocas horas. Estoy experimentando con la fijación de versiones sin usar archivos flake, y fetchGit era la opción más lógica.

@juanringer juanringer changed the title libfetchers: builtins.fetchGit, skip fetching if already cached libfetchers: skip fetching if already cached Jan 12, 2026
@juanringer
Copy link
Author

Looks like evaluation performance is withing margin of error for locked flake inputs.

@juanringer juanringer changed the title libfetchers: skip fetching if already cached libfetchers: skip fetching if narHash and rev are defined Jan 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fetching Networking with the outside (non-Nix) world, input locking

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants