How do I clone a github repo to a folder in my home directory?

I was following through this setup for Doom Emacs but I’m currently stuck with it. I noticed that when I use the fetchGit command, it ends up erroring out saying error: in pure evaluation mode, 'fetchTree' requires a locked input, at /nix/store/8xpb6snxi90adcc2pg6yvnikghdma4bx-source/home-manager/home.nix:74:18 I’m very new to NixOS and I’m not sure what that means exactly. Anyone know how I can modify my config to make it work properly?
I’m using NixOS 23.05 with Home-Manager in standalone and with Flakes


{ config, pkgs, ... }:

  imports = [
  #  ./apps/git.nix

  # Home Manager needs a bit of information about you and the paths it should
  # manage.
  home.username = "novaviper";
  home.homeDirectory = "/home/novaviper";
  # Enable XDG
  xdg.enable = true;

  # This value determines the Home Manager release that your configuration is
  # compatible with. This helps avoid breakage when a new Home Manager release
  # introduces backwards incompatible changes.
  # You should not change this value, even if you update Home Manager. If you do
  # want to update the value, then make sure to first check the Home Manager
  # release notes.
  home.stateVersion = "23.05"; # Please read the comment before changing.

  # The home.packages option allows you to install Nix packages into your
  # environment.
  home.packages = with pkgs; [

    # # Adds the 'hello' command to your environment. It prints a friendly
    # # "Hello, world!" when run.
    # pkgs.hello

    # # It is sometimes useful to fine-tune packages, for example, by applying
    # # overrides. You can do that directly here, just don't forget the
    # # parentheses. Maybe you want to install Nerd Fonts with a limited number of
    # # fonts?
    # (pkgs.nerdfonts.override { fonts = [ "FantasqueSansMono" ]; })

    # # You can also create simple shell scripts directly inside your
    # # configuration. For example, this adds a command 'my-hello' to your
    # # environment:
    # (pkgs.writeShellScriptBin "my-hello" ''
    #   echo "Hello, ${config.home.username}!"
    # '')

  # Home Manager is pretty good at managing dotfiles. The primary way to manage
  # plain files is through 'home.file'.
  home.file = {
    # # Building this configuration will create a copy of 'dotfiles/screenrc' in
    # # the Nix store. Activating the configuration will then make '~/.screenrc' a
    # # symlink to the Nix store copy.
    # ".screenrc".source = dotfiles/screenrc;

    # # You can also set the file content immediately.
    # ".gradle/".text = ''
    #   org.gradle.console=verbose
    #   org.gradle.daemon.idletimeout=3600000
    # '';

  xdg.configFile = {
    "git/config".source = ./dotfiles/git/config;
    "emacs" = {
        source = builtins.fetchGit "";
        onChange = "${pkgs.writeShellScript "doom-change" ''
          export DOOMDIR="${config.home.sessionVariables.DOOMDIR}"
          export DOOMLOCALDIR="${config.home.sessionVariables.DOOMLOCALDIR}"
          if [ ! -d "$DOOMLOCALDIR" ]; then
            ${config.xdg.configHome}/emacs/bin/doom -y install
            ${config.xdg.configHome}/emacs/bin/doom -y sync -u

  home.sessionPath = [ "${config.xdg.configHome}/emacs/bin" ];

  # You can also manage environment variables but you will have to manually
  # source
  #  ~/.nix-profile/etc/profile.d/
  # or
  #  /etc/profiles/per-user/novaviper/etc/profile.d/
  # if you don't want to manage your shell through Home Manager.
  home.sessionVariables = {
    # EDITOR = "emacs";
    DOOMDIR = "${config.xdg.configHome}/doom-config";
    DOOMLOCALDIR = "${config.xdg.configHome}/doom-local";


  # Let Home Manager install and manage itself.
  programs.home-manager.enable = true;

Basically, this means that you have to show to Nix that the output of a function interacting with the internet will always be the same, no matter when it is called.

This is what it means when we say a function or its evaluation are “pure”, and that its output is “reproducible”.

You’re calling builtins.fetchGit just with a repository URL right now, so it will get the latest commit of the master or main branch, and what that commit is might be different in a few hours, so it’s not reproducible just by its input, and thus nix fails in the default “pure evaluation mode”.

There’s two ways around this:

  1. You can call whatever you called when you got this error (I assume nixos-rebuild?) with the --impure flag. This works, but is not recommended, as it means that your system config might randomly break on a future rebuild, and nix will clone the entire repo again on every rebuild because it can’t be sure that the output didn’t change
  2. You add the hash of the actual commit you want to clone with the rev parameter. So your call would look like this instead:
    source = builtins.fetchGit {
      url = "";
      rev = "07fca786154551f90f36535bfb21f8ca4abd5027";

This will make the evaluation of fetchGit pure, so you won’t get the error message, and Nix will only download the repo again if you change the “rev” argument.

1 Like

Ah I didn’t realize that, thanks!