gitignore for Nix


Abstract

Nix, when used as a development build tool, needs to solve the same problem that git does: ignore some files. We’ve extended nix-gitignore so that Nix can more reliably use the configuration that you’ve already written for git.

Introduction

When you tell Nix to build your project, you need to tell it which source files to build. This is done by using path syntax in a derivation or string interpolation.

mkDerivation {
  src = ./vendored/cowsay;
  postPatch = ''
    # Contrived example of using a file in string interpolation
    # The patch file is put in /nix/store and the interpolation
    # produces the appropriate store path.
    patch -lR ${./cowsay-remove-alpaca.patch}
  '';
  # ...
}

This works well, until you find that Nix unexpectedly rebuilds your derivation because a temporary, hidden file has changed. One of those files you filtered out of your git tree with a ‘gitignore’ file…

Nix, as a build tool or package manager, was not designed with any specific version control system in mind. In fact it predates any dominance of git, because Nix’s general solution to the file ignoring problem, filterSource, was already implemented in 2007.

Over the last two to three years, various people have written functions to reuse these gitignore files. We have been using an implementation by @siers over the last couple of months and it has served us well, until we had a gitignore file that wasn’t detected because it was in a parent directory of the source directory we wanted to use.

I was nerd sniped.

Two months later, I finally got around to the implementation and I’m happy to announce that it solves some other problems as well. It reuses the tested rules by siers, doesn’t use import from derivation and can read all the files that it needs to.

Usage

You can import the gitignoreSource function from the repo like below, or use your favorite pinning method.

{ pkgs ? import <nixpkgs> {} }
let
  inherit (pkgs.stdenv) mkDerivation;
  inherit (import (builtins.fetchTarball "https://github.com/hercules-ci/gitignore/archive/master.tar.gz") { }) gitignoreSource;
in
mkDerivation {
  src = gitignoreSource ./vendored/cowsay;
  postPatch = ''
    patch -lR ${./cowsay-remove-alpaca.patch}
  '';
  # ...
}

That’s all there is to it.

It also composes with cleanSourceWith if you like to filter out some other files as well.

Comparison

Here’s a comparison with the pre-existing implementation I found.

The latest up to date comparison table is available on the repo.

Feature \ Implementation cleanSource siers siers recursive icetan Profpatsch numtide this project
Ignores .git ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
No special Nix configuration ✔️ ✔️ ✔️ ✔️ ✔️   ✔️
No import from derivation ✔️ ✔️   ✔️ ✔️ ✔️ ✔️
Uses subdirectory gitignores     ✔️     ✔️ ✔️
Uses parent gitignores           ✔️ ? ✔️
Uses user gitignores           ✔️ ✔️
Has a test suite   ✔️ ✔️ ✔️   ? ✔️
Works with restrict-eval / Hydra ✔️ ✔️   ✔️ ✔️   ✔️
Included in nixpkgs ✔️ ✔️ ✔️        
  Legend
✔️ Supported
✔️ ? Probably supported
  Not supported
? Probably not supported
- Not applicable or depends

Inclusion in Nixpkgs

I think it would be really nice to have this function in Nixpkgs, but it needs to be tested in practice first. This is where you can help out! Please give the project (GitHub) a spin and leave a thumbs up if it worked for you (issue).

Closing thoughts

I am happy to contribute to the friendly and inventive Nix community. Even though this gitignore project is just a small contribution, it wouldn’t have been possible without the ideas and work of siers, icetan, and everyone behind Nix and Nixpkgs in general.

As a company we are working hard to make good products to support the community and companies that want to use Nix. One of our goals is to keep making contributions like this, so please try our binary cache as a service, which is free for open source and just as easy to set up privately for companies. If you have an interest in our Nix CI, please subscribe.

– Robert