Make Home Manager clone some Git repos for my dotfiles

Hi there. I’m not very sure I want to convert every single dotfile I have to the Nix format because firstly I’m not yet entirely sure I want to make the switch to NixOS, and secondly I want my dotfiles to be universal.

Usually, when I install my dotfiles on a Linux machine, I have a folder where all of them get cloned and then I manually symlink every folder that needs to be symlinked to its proper place. I’d like to replicate that since I edit the cloned Git repos in my homedir when I want changes to my dotfiles and they automatically apply as well (basically how symlinks work).

I thought this would be something very trivial, but a couple of searches later I realised that I either don’t know how to search well for this problem in particular, or that not many people do this. So, I decided to create this topic.

I think that’s the crux of the issue. It’s going to be quite awkward, I can see ~three ways of doing this:

  1. Make derivations for each of the git repos (to enable nix to download them), and use home.file to symlink them into place
    • This is the most idiomatic approach, but it results in read-only git repos that you can no longer edit.
  2. Make derivations again, but this time use home.activation to clone the derivations into place at activation time.
    • This still enables downloads with nix.
    • It forces the problem of managing the deployed repositories into your hands, since editing them will make them desync with the nix derivations. To resolve this, you can:
      • Only copy the repos into place if they aren’t present yet, in which case the nix-deployed repositories will go out of date and on redeployment things may not actually work.
      • Always override the deployed repositories, in which case you might lose changes if you’re not careful.
  3. Use home.activation to clone the repositories at activation time
    • This goes actively against what home.activation is supposed to do. It will still work though.
    • Alternatively you could write a systemd service that periodically downloads git repos to not break home.activation.

Speaking from experience though, as I also started out thinking it would be best to keep my dotfiles as agnostic as possible, I don’t think it’s a good idea.

The problem with the approach as a whole is that you simply will not get one, declarative world view over your configuration. You’ll still have messy drift between systems, and no guarantee that you can get back to a specific version or anything. You also can’t use the nix language to programmatically change things depending on host or such.

The only benefit of using home-manager for this is that you’ll have a script that puts your directories in place, which you could frankly just write by hand if you’re not going to use the rest of home-manager, which you will be reluctant to do because the options write dotfiles for you. Yet, the primary advantage of home-manager in the long run is that you can get reasonable configuration files that are maintained by more people than just you.

You don’t gain much from keeping your dotfiles separate either, except that you do not need to evaluate a nix expression to get your dotfiles. Nix can be deployed on most platforms out there, and even when not you can still precompile your dotfiles, so there should be little loss of “universality”.

The only real benefit is that you can edit symlinked files and have instant configuration updates. I get that this is personal preference, but frankly I find that after initial experimentation changes are rare enough that the ~2 second delay is rarely an issue for me. Especially since a lot of the things I run aren’t capable of watching their config files and updating instantly anyway.

I understand why a solution like mine is completely undesirable, but since I don’t want to convert ~800 lines of Zsh configs and ~1800 lines of Neovim configs to say the two largest ones, I’d like the approach of being able to modify some Git repos in my home folder and just have them being used by the programs.

I wouldn’t like to have to commit & push every single little change I make to a Git server just so that Home Manager can then pull them back again from that same Git server I just pushed to just to have it done more like the Nix way without the declarative configuration either, because there are many periods of time where I change many things quickly.

I don’t mind having Home Manager dumbly cloning my dotfiles’ Git repos and then having to manually keep the repos up to date on every host since I really rarely use more than one host and that’s what I have been doing for years anyways.

I wouldn’t mind to have to run home-manager switch every time I update something in my configs though, so if there’s a way to modify my dotfiles in their Git cloned folders and then have Home Manager put them in the Nix Store, I’ll take that too. Symlinks are not a must, I was just describing what I’ve been using before.

So what would be the best way to do this in this case?

Why on earth would you do that? Just keep a clone of your home-manager repository locally, there’s no networking required.

The overhead is waiting for nix to rebuild (after you run home-manager switch) when you change to the new state. It doesn’t involve networking, and you don’t need to touch git at all to rebuild. Hell, you don’t even need to keep your configuration in a git repo at all if you don’t like version control (though I gather you do, and you also can keep it version controlled - it’s just text files).

Yeah, in that case I’d suggest creating a directory called legacy-dotfiles or something in your overall home-manager based dotfiles repository, and copy over all the repositories you want into that directory. You can even keep them as git submodules.

Then you would configure home-manager to symlink them into the correct location, for example for neovim:

{
  xdg.configFile."nvim".source = ./legacy-dotfiles/nvim;
}

After a home-manager switch your neovim dotfiles would then be symlinked to ~/.config/nvim (or whatever you set the xdg.configHome option to). It would be read-only, so you can’t directly change the files in ~/.config/nvim, but you can modify them offline in $REPO/legacy-dotfiles/nvim and then switch over with home-manager switch again.

Great! This is what I want to do. Is there a way to make Nix clone my Git repos the first time the system gets installed?

I’m not exactly sure what you’re asking…

If your repos are submodules of your general home-manager dotfiles repo as I suggest, you would clone them all in one go with git clone --recursive.

You need to clone the dotfiles repo to be able to run home-manager on it anyway, so I struggle to imagine a scenario in which they wouldn’t be cloned when your dotfiles are installed?

Or are we talking about a NixOS scenario? In that case, you can use the NixOS integration module to install your dotfiles together with the rest of your NixOS configuration.

If you do the latter, I would recommend not putting your NixOS or home-manager configuration in their default locations, though, and just placing them somewhere in $HOME so you can easily edit them. You can build your configuration from any directory, you just need to learn about -I nixos-config=<path> or flakes.

Or do you want everything to be part of the NixOS install CD? In that case you can relatively easily make your own custom NixOS install CD that contains your repositories, as well.

Currently I have 3 (soon 4 with the NixOS configs once I get around to publishing them) Git repos with dotfiles. One for the Zsh configs, one for the Neovim config and one for the Hyprland compositor with all the dotfiles for the programs I use with it. I keep all these repos in a folder with dotfiles in my homedir.

What I’d like to achieve with NixOS in general (probably there’s steps in this that are not a task for Home Manager) is to have that folder made automatically, clone all the Git repos with dotfiles inside it and then have the dotfiles I specify get put into their right places in the Nix store, and then linked into my homedir (which you’ve clarified how to do)

So, put a home.nix file in that dotfiles directory, and run git init in it. Git should pick up on the fact that there are recursive git repos in this directory, and turn them all into so-called “submodules”.

Submodules are exactly that - recursive git directories. You just need to set up their origins correctly, and then in the future if you git clone --recursive the home-manager dotfiles directory it will clone all the other repos together with it, correctly set up to be installed.

You can even forego the nested git repos completely and just keep the top-level one, which is what I do.

Is this sufficient to fulfill:

If not, where do you want the dotfiles to come from? You’ll have to do something to get the home-manager configuration, unless you intend to rewrite it from scratch every time you deploy it, a recursive git clone sounds like it solves all your problems.

Or is it that you want to have some process to copy the dotfiles directory you’re currently inside of to the installed system before you reboot for the first time?

That’s just cp -r . /mnt/home/andy/.local/src/dotfiles or such, you could add that as a script to your dotfiles directory that you just execute after nixos-install, or if you want to go completely overboard I guess you could write a custom NixOS install CD that adds that line to the nixos-install script.

Either way, I’m fairly certain what you want is possible, you might just need to try it to see how it all works so you can come up with the exact process that’s right for you.

Well, now you’ve made me publish my NixOS configs to GitHub just to show you the structure.

Before this thread, I wanted this repo in my dotfiles folder in my homedir too, and then I wanted to basically:

ln -s ~andy3153/src/nixos/nixos-rice/etc/nixos /etc
ln -s ~andy3153/src/nixos/nixos-rice/home/andy3153/.config/home-manager ~andy3153/.config

Now after this conversation, I’m realizing I want this done automatically by something in the configuration.nix too, after the installation through the live usb