Accessing .git directory in flake with local source

I have a flake with src = ./.. When the source is copied over to the store, the .git directory is removed.

I know there are issues with keeping that directory around, but is there a way to force this behaviour (like leaveDotGit for fetchFromGitHub)? There are packages around that then remove .git in a postFetch, which seems to be sufficient to restore purity?

The reason I’m wanting to do this is that the crate I’m trying to package runs git as part of the build (to have the hash in the output of --version), and I don’t see another way to make this work.

I remember running into this as well, and as far as I know there is no way to leave the .git directory around for flake inputs atm, unfortunately.

Have you found workarounds for the git rev-parse HEAD scenario, where git is run as part of the build?

At some points people mentionned that it could be possible to implement a tool that fake git. For instance by pre-recording git outputs and playing them in a dummy executable. It may even be possible to semi-automate the process by generating a json file while compiling in a nix shell, and then reuse this in the derivation, but it may be a bit annoying to do everytime we upgrade the package. At least the hash of the derivation is guaranteed to never shift.

1 Like

Use the following in the nativeBuildInputs:

writeShellScriptBin "git" ''
  echo "${theInput.rev}"
''

Extend the script as necessary for more complex “git queries”.

Alternatively patch the build process of the project to not rely on git at all for the version, but instead replace the git run with a hardcoded value based on your version field.

1 Like

The problem is that what I’m trying to access is not an input, it’s src = ./..

Git is used by the to-be-packaged crate to output something like foobar-v2-deadbeef-x86_64-linux-gnu, i.e. to have greater granularity than just the version.

I could manually keep the commit hash in the flake in sync and replicate the logic, but that’s just horrible.

Could nix expose the git hash, maybe as an env var, before deleting the directory? So one could access it from within the package and do stuff with it.

self is also an input. Though then you need to do something like self.rev or "dirty".

1 Like

Thank you so much @NobbZ, that’s a pretty elegant technique :slight_smile:

Argh. I also want this, but I actually want to include the .git directory in a build’s output (I want to include a copy of my flake, with git history, on the NixOS install media that I’m building from it).

If you use a path: url it will copy the entire path including .git into the store.

(PS: I’m not a mod here, but necroing an old post with a new issue is usually considered bad form on most help forums. Your question merits a new topic.)

Interesting! With flake = false; I can even have path:. without a circular reference problem, since that copy of the flake doesn’t actually get evaluated.

As for necroposting, I suppose you’re right. I didn’t really see this thread as resolved in the sense that OP’s original ask was never satisfied, and it was the most relevant result to all of my searches for this exact issue. I figured that if it were resolvable as asked, some future searchers might benefit from seeing that resolution here when they see this post.

Looking at it again now, though, OP did mark this isaue resolved since their concrete problem was solved. I guess I should have made a new post and linked to this one.

Anyhow thanks for letting me know that other workaround. :slight_smile:

Edit: That workaround doesn’t work; .git dir still gets stripped when I add a flake input with path:.. :upside_down_face:

I don’t know about flakes, but we figured the following one line to get git output:

git-rev = pkgs.runCommand "gitrev" { buildInputs = [pkgs.git]; } "git --git-dir ${./.git} rev-parse HEAD > $out";

This avoids the implicit .git stripping because it explicitly uses it as --git-dir argument.

1 Like