Nix: Configuring git

Nix and Home Manager - Getting setup
Nix: Configuring program specific configurations - The basics
➜ Nix: Configuring git

Git is one of the first things I reach for when setting up a new machine, which makes it a natural fit for Home Manager. Instead of copying .gitconfig between machines or running git config --global commands by hand, we can declare the whole setup in home.nix and have it applied automatically.

programs.git

Home Manager has first-class support for git via programs.git. At minimum we need a name and email:

$ vim ~/.config/home-manager/home.nix
{ config, pkgs, ... }:

{
  programs.git = {
    enable = true;
    userName = "Your Name";
    userEmail = "you@example.com";
  };
}

Save and apply:

$ home-manager switch

Verify the result:

$ git config --global user.name
Your Name
$ cat ~/.config/git/config

Notice that like bat in the previous article, the generated config file is a symlink into the Nix store. Home Manager owns it — editing ~/.config/git/config directly would work temporarily but would be overwritten on the next home-manager switch.

Global gitignore

Rather than adding OS and editor noise to every repo’s .gitignore, we can declare a global ignore list once:

programs.git = {
  enable = true;
  userName = "Daniel Tucker";
  userEmail = "you@example.com";

  ignores = [
    ".DS_Store"
    "*.swp"
    ".direnv"
    ".envrc"
  ];
};

Home Manager writes this to ~/.config/git/ignore and sets core.excludesFile automatically. No manual git config --global core.excludesFile required.

Aliases

Aliases go directly in the git block:

programs.git = {
  enable = true;
  userName = "Daniel Tucker";
  userEmail = "you@example.com";

  ignores = [
    ".DS_Store"
    "*.swp"
    ".direnv"
    ".envrc"
  ];

  aliases = {
    st = "status";
    co = "checkout";
    lg = "log --oneline --graph --decorate --all";
    undo = "reset HEAD~1 --mixed";
  };
};

Test one:

$ git lg

Extra configuration

For anything not directly exposed by the programs.git options, extraConfig accepts arbitrary git config as an attribute set:

programs.git = {
  enable = true;
  userName = "Daniel Tucker";
  userEmail = "you@example.com";

  ignores = [
    ".DS_Store"
    "*.swp"
    ".direnv"
    ".envrc"
  ];

  aliases = {
    st = "status";
    co = "checkout";
    lg = "log --oneline --graph --decorate --all";
    undo = "reset HEAD~1 --mixed";
  };

  extraConfig = {
    init.defaultBranch = "main";
    pull.rebase = true;
    rebase.autoStash = true;
    core.editor = "vim";
  };
};

Run home-manager switch and verify:

$ git config --global init.defaultBranch
main
$ git config --global pull.rebase
true

Signing commits with GPG

If you sign commits, Home Manager can wire up the signing key too. First make sure gnupg is in your packages, then add the signing block:

{ config, pkgs, ... }:

{
  home.packages = [ pkgs.gnupg ];

  programs.git = {
    enable = true;
    userName = "Your Name";
    userEmail = "you@example.com";

    signing = {
      key = "YOUR_GPG_KEY_ID";
      signByDefault = true;
    };

    extraConfig = {
      init.defaultBranch = "main";
      pull.rebase = true;
      rebase.autoStash = true;
      core.editor = "vim";
    };
  };
}

You can find your key ID with gpg --list-secret-keys --keyid-format=long. Replace YOUR_GPG_KEY_ID with the long-form ID for the key associated with your git email.

The wrap-up

In conclusion, we have moved our entire git configuration into home.nix. Name, email, global ignores, aliases, extra settings, and optional GPG signing are all declared in one place. A fresh home-manager switch on any machine gives an identical git setup — no manual steps, no forgotten flags.

From here the pattern extends to any other program with a Home Manager module: declare it, switch, verify.

For feedback, ping me on Mastodon @tuck@fosstodon.org .