GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — GitHub - cachix/git-hooks.nix: Seamless integration of https://pre-commit.com git hooks with Nix.

BranchesTags
Open more actions menu

Latest commit

 

History

1,265 Commits
1,265 Commits

Folders and files

NameName
Last commit message
Last commit date
.github
.github
 
 
dev
dev
 
 
modules
modules
 
 
nix
nix
 
 
template
template
 
 
.editorconfig
.editorconfig
 
 
.envrc
.envrc
 
 
.gitignore
.gitignore
 
 
.typos.toml
.typos.toml
 
 
CHANGELOG.md
CHANGELOG.md
 
 
LICENSE
LICENSE
 
 
README.md
README.md
 
 
default.nix
default.nix
 
 
flake-module.nix
flake-module.nix
 
 
flake.lock
flake.lock
 
 
flake.nix
flake.nix
 
 
pre-commit.png
pre-commit.png
 
 
shell.nix
shell.nix
 
 

Repository files navigation

Seamless integration of git hooks with Nix

pre-commit.png

Features

  • Trivial integration for Nix projects (wires up a few things behind the scenes)

  • Provide a low-overhead build of all the tooling available for the hooks to use (naive implementation of calling nix-shell does bring some latency when committing)

  • Common hooks for languages like Python, Haskell, Elm, etc. See all hook options

  • Run hooks as part of development and during CI

  • Support for alternative pre-commit implementations, like prek.

Getting started

devenv.sh

{ inputs, ... }:

{
  git-hooks.hooks = {
    # Format Nix code
    nixfmt.enable = true;

    # Format Python code
    black.enable = true;

    # Lint shell scripts
    shellcheck.enable = true;

    # Execute shell examples in Markdown files
    mdsh.enable = true;

    # Override a package with a different version
    ormolu.enable = true;
    ormolu.package = pkgs.haskellPackages.ormolu;

    # Some hooks have more than one package, like clippy:
    clippy.enable = true;
    clippy.packageOverrides.cargo = pkgs.cargo;
    clippy.packageOverrides.clippy = pkgs.clippy;
    # Some hooks provide settings
    clippy.settings.allFeatures = true;

    # Define your own custom hooks
    # See all options: https://github.com/cachix/git-hooks.nix#custom-hooks
    my-custom-hook = {
      enable = true;
      entry = "./on-pre-commit.sh";
    };
  };

  # Use alternative pre-commit implementations
  git-hooks.package = pkgs.prek;
}

See getting started.

Flakes support

Given the following flake.nix example:

{
  description = "An example project";

  inputs = {
    systems.url = "github:nix-systems/default";
    git-hooks.url = "github:cachix/git-hooks.nix";
  };

  outputs =
    {
      self,
      systems,
      nixpkgs,
      ...
    }@inputs:
    let
      forEachSystem = nixpkgs.lib.genAttrs (import systems);
    in
    {
      # Run the hooks with `nix fmt`.
      formatter = forEachSystem (
        system:
        let
          pkgs = nixpkgs.legacyPackages.${system};
          config = self.checks.${system}.pre-commit-check.config;
          inherit (config) package configFile;
          script = ''
            ${pkgs.lib.getExe package} run --all-files --config ${configFile}
          '';
        in
        pkgs.writeShellScriptBin "pre-commit-run" script
      );

      # Run the hooks in a sandbox with `nix flake check`.
      # Read-only filesystem and no internet access.
      checks = forEachSystem (system: {
        pre-commit-check = inputs.git-hooks.lib.${system}.run {
          src = ./.;
          hooks = {
            nixfmt.enable = true;
          };
        };
      });

      # Enter a development shell with `nix develop`.
      # The hooks will be installed automatically.
      # Or run pre-commit manually with `nix develop -c pre-commit run --all-files`
      devShells = forEachSystem (system: {
        default =
          let
            pkgs = nixpkgs.legacyPackages.${system};
            inherit (self.checks.${system}.pre-commit-check) shellHook enabledPackages;
          in
          pkgs.mkShell {
            inherit shellHook;
            buildInputs = enabledPackages;
          };
      });
    };
}

Add /.pre-commit-config.yaml to .gitignore. This file is auto-generated from the Nix configuration and doesn't need to be committed.

Enter a development shell with pre-commit hooks enabled:

nix develop

Run all hooks sandboxed:

nix flake check

Keep in mind that nix flake check runs in a sandbox. It doesn't have access to the internet and cannot modify files. This makes it a poor choice for formatting hooks that attempt to fix files automatically, or hooks that cannot easily be packaged to avoid impure access to the internet.

A better alternative in such cases is to run pre-commit through nix develop:

nix develop -c pre-commit run -a

Or configure a formatter like in the example above and use nix fmt:

nix fmt

flake-parts

If your flake uses flake-parts, we provide a flake-parts module as well. Checkout ./template/flake.nix for an example.

Nix

  1. Optionally use binary caches to avoid compilation:

    nix-env -iA cachix -f https://cachix.org/api/v1/install
    cachix use pre-commit-hooks
  2. Integrate hooks to be built as part of default.nix:

     let
       nix-pre-commit-hooks = import (builtins.fetchTarball "https://github.com/cachix/git-hooks.nix/tarball/master");
     in {
       # Configured with the module options defined in `modules/pre-commit.nix`:
       pre-commit-check = nix-pre-commit-hooks.run {
         src = ./.;
         # If your hooks are intrusive, avoid running on each commit with a default_states like this:
         # default_stages = ["manual" "pre-push"];
         hooks = {
           elm-format.enable = true;
    
           # override a package with a different version
           ormolu.enable = true;
           ormolu.package = pkgs.haskellPackages.ormolu;
           ormolu.settings.defaultExtensions = [ "lhs" "hs" ];
    
           # some hooks have more than one package, like clippy:
           clippy.enable = true;
           clippy.packageOverrides.cargo = pkgs.cargo;
           clippy.packageOverrides.clippy = tools.clippy;
           # some hooks provide settings
           clippy.settings.allFeatures = true;
         };
       };
     }

    Run $ nix-build -A pre-commit-check to perform the checks as a Nix derivation.

  3. Integrate hooks to prepare environment as part of shell.nix:

     let
       pre-commit = import ./default.nix;
     in (import <nixpkgs> {}).mkShell {
       shellHook = ''
         ${pre-commit.pre-commit-check.shellHook}
       '';
       buildInputs = pre-commit.pre-commit-check.enabledPackages;
     }

    Add /.pre-commit-config.yaml to .gitignore.

    Run $ nix-shell to execute shellHook which will:

    • build the tools and .pre-commit-config.yaml config file symlink which references the binaries, for speed and safe garbage collection
    • provide the pre-commit executable that git commit will invoke

Optional

Direnv

.envrc:

use nix

Custom hooks

Sometimes it is useful to add a project specific command as an extra check that is not part of the pre-defined set of hooks provided by this project.

Example configuration:

 let
   nix-pre-commit-hooks = import (builtins.fetchTarball "https://github.com/cachix/git-hooks.nix/tarball/master");
 in {
   pre-commit-check = nix-pre-commit-hooks.run {
     hooks = {
       # ...

       # Example custom hook for a C project using Make:
       unit-tests = {
         enable = true;

         # The name of the hook (appears on the report table):
         name = "Unit tests";

         # The command to execute (mandatory):
         entry = "make check";

         # The pattern of files to run on (default: "" (all))
         # see also https://pre-commit.com/#hooks-files
         files = "\\.(c|h)$";

         # List of file types to run on (default: [ "file" ] (all files))
         # see also https://pre-commit.com/#filtering-files-with-types
         # You probably only need to specify one of `files` or `types`:
         types = [ "text" "c" ];

         # Exclude files that were matched by these patterns (default: [ ] (none)):
         excludes = [ "irrelevant\\.c" ];

         # The language of the hook - tells pre-commit
         # how to install the hook
         # (default: "system", or "unsupported" for pre-commit >= 4.4.0)
         # see also https://pre-commit.com/#supported-languages
         language = "unsupported";

         # Set this to false to not pass the changed files
         # to the command (default: true):
         pass_filenames = false;

         # Which git hooks the command should run for (default: [ "pre-commit" ]):
         stages = ["pre-push"];
       };
     };
   };
 }

Custom hooks are defined with the same schema as pre-defined hooks.

Note on language = "system" vs "unsupported":

Pre-commit >= 4.4.0 renamed "system" to "unsupported".

This does not mean deprecated — "unsupported" is just a new name to reflect that when using this language, pre-commit does not provision the tools, and using externally managed tools (e.g. via Nix) is not an officially supported workflow.

Both values are functionally equivalent. The default is set automatically based on the pre-commit package version.

We recommend switching to prek.

Built-in hooks

Ansible

  • ansible-lint

C/C++/C#/ObjC

  • clang-format.
    You may restrict which languages should be formatted by clang-format using clang-format.types_or. For example to check only C and C++ files:

    clang-format = {
      enable = true;
      types_or = lib.mkForce [ "c" "c++" ];
    };

    Otherwise, the default internal list is used which includes everything that clang-format supports.

  • clang-tidy

  • cmake-format

Clojure

  • cljfmt
  • zprint

Crystal

  • crystal

CUE

  • cue-fmt

Dart

  • dart analyze
  • dart format

Dhall

  • dhall format

Dockerfile

  • hadolint

Editorconfig

  • eclint
  • editorconfig-checker

Elm

  • elm-format
  • elm-review
  • elm-test

Elixir

  • credo
  • dialyzer
  • mix-format
  • mix-test

Fortran

  • fprettify

Git

  • annex
  • check-merge-conflicts
  • commitizen
  • convco
  • forbid-new-submodules
  • gitleaks
  • gitlint
  • gptcommit
  • no-commit-to-branch

Golang

  • gofmt: Runs go fmt
  • golangci-lint
  • golines
  • gotest: Runs go test
  • govet
  • revive
  • staticcheck

Haskell

  • cabal-fmt
  • cabal-gild
  • cabal2nix
  • fourmolu
  • hindent
  • hlint
  • hpack
  • ormolu
  • stylish-haskell

HTML

  • html-tidy

Java

  • google-java-format

JavaScript/TypeScript

  • biome
  • denofmt
  • denolint
  • eslint
  • oxfmt
  • oxlint
  • rome: (alias to the biome hook)

JSON

  • check-json
  • pretty-format-json

Julia

  • JuiaFormatter.jl

LaTeX

  • chktex
  • lacheck
  • latexindent

Link checker

  • lychee
  • mkdocs-linkcheck

Lua

  • luacheck
  • lua-ls
  • selene
  • stylua

Markdown

  • comrak
  • markdownlint
  • mdformat
  • mdl
  • mdsh
  • panache
  • rumdl

Nix

  • alejandra
  • deadnix
  • flake-checker
  • nil
  • nixf-diagnose
  • nixfmt
  • nixpkgs-fmt
  • statix

Nushell

  • nu-check
  • nu-lint
  • nufmt

OCaml

  • dune-fmt
  • dune-opam-sync
  • ocp-indent
  • opam-lint

PHP

  • phpcbf
  • php-cs-fixer
  • phpcs
  • phpstan
  • psalm

Purescript

  • purs-tidy

Python

  • autoflake
  • black
  • check-builtin-literals
  • check-docstring-first
  • check-python
  • fix-encoding-pragma
  • flake8
  • flynt
  • isort
  • mypy
  • name-tests-test
  • poetry-check: Run poetry check.
  • poetry-lock: Run poetry lock.
  • pylint
  • pyright
  • python-debug-statements
  • pyupgrade
  • ruff
  • ruff-format
  • single-quoted-strings
  • sort-requirements-txt
  • ty
  • uv

R

  • air

Rego (Open Policy Agent)

  • regal

Rust

  • cargo-check
  • cargo-sort
  • clippy
  • rustfmt

Secret detection

  • pre-commit-ensure-sops
  • ripsecrets
  • trufflehog: Secret scanner

Shell

  • bats
  • beautysh
  • shellcheck
  • shfmt

Spell checker

  • cspell
  • hunspell
  • proselint
  • typos
  • vale

Terraform

  • terraform-format: built-in formatter (using OpenTofu's fmt or Terraform's fmt)
  • terraform-validate: built-in validator (using OpenTofu's validate Terraform's validate)
  • tflint

TOML

  • check-toml
  • taplo fmt

Typst

  • typstyle

YAML

  • check-yaml
  • sort-simple-yaml
  • yamlfmt
  • yamllint

Various other hooks

  • actionlint
  • action-validator
  • chart-testing
  • check-added-large-files
  • check-case-conflicts
  • check-executables-have-shebangs
  • checkmake
  • check-shebang-scripts-are-executable
  • check-symlinks
  • check-vcs-permalinks
  • check-xml
  • circleci
  • conform
  • detect-aws-credentials
  • detect-private-keys
  • end-of-file-fixer
  • fix-byte-order-marker
  • headache
  • hledger-fmt
  • keep-sorted
  • mixed-line-endings
  • mkdocs-linkcheck
  • openapi-spec-validator
  • prettier
  • reuse
  • sort-file-contents
  • tagref
  • topiary
  • treefmt
  • trim-trailing-whitespace
  • woodpecker-cli-lint
  • zizmor

Performance benchmarks

See the benchmark toolset to compare Nix evaluation and hook execution with pre-commit, prek, and nixhooks without flakes.

Contributing hooks

Everyone is encouraged to add new hooks.

Have a look at the existing hooks and the options.

There's no guarantee the hook will be accepted, but the general guidelines are:

  • Nix closure of the tool should be small e.g. < 50MB. A problematic example:
  $ du -sh $(nix-build -A go)
  463M  /nix/store/v4ys4lrjngf62lvvrdbs7r9kbxh9nqaa-go-1.18.6
  • The tool must not be very specific (e.g. language tooling is OK, but project specific tooling is not)
  • The tool needs to live in a separate repository (even if a simple bash script, unless it's a oneliner)

About

Seamless integration of https://pre-commit.com git hooks with Nix.

Topics

nixpre-commit

Resources

Readme
Apache-2.0 license
Activity
Custom properties

Stars

883 stars

Watchers

4 watching

Forks

229 forks
Report repository

Releases

Packages

Used by

Contributors

Languages

You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.