Does fetchFromGithub ignore `rev` when a derivation with equivalent `sha256` is present?

I notice that when using fetchFromGithub, changing the rev field without changing the sha256 field builds without error, while I expected it to crash. I also notice that the build is equal to the one with the previous value of rev, as if I hadn’t changed the value.

Is the rev field ignored when there is already a realized derivation in the nix store that matches the sha256?

If so, then I guess the build will crash on another machine where there is no previous derivation matching the sha256? Can I force the check that the sha256 is the right one for the given rev to ensure reproducibility?

1 Like

From my own experiences, yes. But I don’t know why. I expect a change in any field in fetchFromGithub (and similar) would yield a different derivation hash. I’ve had multiple occasions where I need a build to crash to see what must be fixed when bumping a version, so I usually just replace a random character in rev to force the rebuild. Not very elegant. Is there a more convenient way?

By providing the sha you tell nix, that an output will be produced with exactly this hash. Due to the store beeing content addressed, it won’t rebuild content that it thinks it already has.

By just changing the rev, nix thinks it would produce the same output anyway, so why bother?

Because fetchFromGitHub is a fixed-output derivation, so the hash is the hash of the output path and not based on the derivation itself. Among other things, this allows changing various aspects of the fetcher without invalidating the hash. E.g. fetchFromGitHub uses fetchzip to fetch and unpack a tarball (unless submodules are fetched). If GitHub changed the URL template for retrieving tarballs, then only the fetchFromGitHub derivation would need to be modified and not the sha256 attributes in the many derivations that use fetchFromGitHub.

This property can also be exploited to e.g. implement fallbacks, such as retrieving sources from the Software Heritage.

Yeah, there’s lib.fakeSha256 and lib.fakeSha512 which is just a string of repeating 0s, which you can set the sha field to temporarily while you’re making changes.

Also:

You can also pass a name attribute to fetchFromGitHub, and it will invalidate an existing fixed-derivation:

  src = fetchFromGitHub = {
    owner = "someone";
    repo = "my-project";
    rev = "v${version}";
    sha256 = "...";
    name = "${pname}-${version}";
  };

by default, fetchFromGitHub will default the name to source (since it’s not aware of the surrounding package context). So, by making it “aware” of the package name and version, you can create a dependency on those things matching.

1 Like