What does "warning: Git tree '/a/path' is dirty" mean exactly?

Couldn’t find an official definition in official git documentation resources, but there were 2 mentions1 that seem to be consistent with Nix’s usage:

A git repo is dirty if there are modified tracked files and/or staged changes, but untracked content doesn’t count. Or, to put in another, a repo is clean if the output of git diff-index HEAD2 is empty.

[1]: “dirty state of your working directory — that is, your modified tracked files and staged changes” and “not considered dirty when they only contain untracked content

[2]: nixos/nix issue #4140: “We use git diff-index HEAD to detect whether a tree is dirty.

That’s exactly what it means in nix, as you mention :slight_smile:

Specifically, that warning pops up when you build a flake (and probably perform certain other operations on them, like nix flake check), if that flake is a git repository and git considers it “dirty” (i.e., modified, except for files that git has not yet been told to track with git add).

The warning is probably there because nix is supposed to make sure that it builds exactly the state of the flake’s git repository - in pursuit of reproducibility it was decided that nix should add flakes to the store before building them, exactly as if someone was cloning your repository, so that you don’t get surprised by missing files down the line.

It would be really annoying if you had to make a commit for every tiny change though, so nix will build dirty repositores for you anyway (but un-tracked files will be missing).

The warning makes sure that you know your repository currently isn’t as reproducible as nix would like, despite its best efforts.

Or at least that’s been my interpretation.

2 Likes

Thanks for the extra info! When I was looking around online, every mention I found was in the context of flakes (e.g., Flakes: why do I consistently see warnings about the git tree being dirty?).

For completeness sake, I stumbled upon it while playing with builtins.fetchGit to see what happens fetching local repos of varying internal states, and when the repo was “dirty”, the builtin’s behaviour would change:

  • The currently checked-out branch in the my-project repo is feature, with only a couple untracked files, but in otherwise pristine state, and the command below indeed retrieves the snapshot at the HEAD of feature:

    nix-repl> builtins.fetchGit ~/clones/my-project
    
    { lastModified     = 1651372838;
      lastModifiedDate = "20220501024038";
      narHash          = "sha256-ejxD1ZjnbRBsvi5NJYhLPQ9FGgORFD/kH10boQxqjVI=";
      outPath          = "/nix/store/x6zcxzmjc340n5ycmgqylvw1j2pg0jkn-source";
      rev              = "f9af46639a9bb5fb22705ebdfd25783866e22c0f";
      revCount         = 36;
      shortRev         = "f9af466";
      submodules       = false;
    }
    
  • In contrast, the current working directory here is a clone of the nixos/nix repo on a branch containing my very in-progress experimental changes:

    nix-repl> builtins.fetchGit {url=./.;}
    
    warning: Git tree '/home/toraritte/clones/nix' is dirty
    { lastModified     = 1658169134; 
      lastModifiedDate = "20220718183214";
       narHash         = "sha256-Vw4lSkslmDIRcHQEO7uSiEV53vYJszVWXeHmFE4/Pww="; 
       outPath         = "/nix/store/74b2zy6vrh463mrbr4p7mwrvjg75967b-source";
       rev             = "0000000000000000000000000000000000000000";
       revCount        = 0;
       shortRev        = "0000000"; 
       submodules      = false; 
    }
    
1 Like