There are many options available to manage dotfiles. I have been using chezmoi for a while now and I am quite happy with it. In this post I will explain how I have set up chezmoi to manage my dotfiles.
I have tried several different approaches, including doing nothing - basically
just making sure I had a backup somewhere. I’ve also tried a simple shell script
that would manage symlinks for me. I’ve also tried GNU Stow.
There are several reasons I don’t like stow
but this post isn’t about bashing
stow
. I started to look into Nix HomeManager but I didn’t want to go all in on
Nix. Nix seemed to all invasive and “heavyweight”. So what are my requirements?
Requirements
Must-haves
My requirements are quite simple:
- CLI - there must be a command line interface
- cross-platform - I want to be able to use the same tool on Linux, macOS and Windows
- free and open source
- version control integration - I want to have the history of my dotfiles
- rollback - I want to be able to rollback changes
- sync - I want to be able to sync my dotfiles across multiple machines
Nice to haves
- secret management - it would be nice to have sensitive values encrypted
Chezmoi
I’m not sure how I first heard of chezmoi. I probably read some blog or saw a video on YouTube. At the time I was managing dotfiles with my own shell script. I was manually saving to GitHub. This met my “must-have” requirements, but obviously it was less than ideal since it was manual. Chezmoi seemed to meet all my requirements including the nice-to-haves. I decided to give it a try.
Download and install
Chezmoi supports various Linux distros and MacOS and Windows. The download
instructions give all the details. I use
brew
even on Linux so I installed chezmoi with brew install chezmoi
.
The chezmoi CLI is called … chezmoi
. Surprise! You can verify that it is
installed and in your path by checking the version:
Initial setup
With chezmoi installed, the next step is to initialize chezmoi. This is done
with the chezmoi init
command. This creates a directory $HOME/.local/share/chezmoi
and initializes it as a Git repo. The chezmoi cd
command creates a new shell
and changes to that chezmoi directory. This is where chezmoi will manage your
configuration.
You are now ready to add whatever config you want to manage with chezmoi.
An aside on the "architecture" of chezmoi.
Chezmoi has a source state and a target state. The source state is the content stored in ~/.local/share/chezmoi while the target state is the content in your filesystem where the “real” files are. The source and target state can be out of sync for various reasons, some good and some not so good. You may legitimately want to have different content as you work on some config changes before you want your changes to take effect. You may also have made changes to the target because you forgot to use the chezmoi
edit
command (see below) and just edited the target file directly. If you do forget to use thechezmoi edit
command, you can use thechezmoi re-add
command to update the source state with the target state.
Adding configuration
To add a file to chezmoi use the chezmoi add
command. This will create a copy
of the file in the chezmoi directory, creating any necessary directories and if
the file is literally a dotfile (i.e. it starts with a ’.’) it will be renamed
to start with the word ‘dot’. For example,
Let’s add a few more files. If including files in a subdirectory, you can just give the subdirectory and it will recurse and add all the files. Be careful though because this will include any dotfiles in the directory, including a .git directory for example.
There are many options to the add
command which you can see with chezmoi add --help
,
such as to be prompted for each file it will add, or whether to follow symlinks.
To see what files are under chezmoi’s control use the chezmoi managed
command.
Integrating with remote Git repo
As mentioned, chezmoi initializes the chezmoi directory as a Git repo. If you
want to point that to a remote such as GitHub, use standard Git commands. For
example, go to your GitHub and create a repo called dotfiles
(or whatever) and
then add that as a remote to chezmoi and push …
Correction
In the original version of this post I said that there was a builtin chezmoi command ‘push’ (e.g.
chezmoi push
) to push git changes to your remote. This was incorrect. I had an alias for that:alias cpush='chezmoi git push'
which made me think there was achezmoi push
.
You do not need to be in the chezmoi directory to use Git commands. You can use
chezmoi git
to execute git commands as if you were in the chezmoi directory:
Initializing from Git
Once you have your configuration in GitHub or whichever service you use, you can
then initialize chezmoi on a new machine using the chezmoi init
command and
providing the Git URL of your repository e.g.
Updating your dotfiles
Configuration is rarely static. When you want to update some configuration file,
you use the chezmoi edit
command. This will open the file in your default
editor. Changes made are only in the source state. The target(s) have not been
updated. When you are ready to update the target state, you use the chezmoi apply
command. If you don’t remember what needs to be applied or generally what
the state is of your configuration, you can use the chezmoi status
command.
This will list files that are out of sync. You can also use the chezmoi diff
command which will display the changes of one or all of your configuration files.
You can do this manually to see what chezmoi is doing under the hood:
Configuration and nvim integration
Chezmoi configuration
The chezmoi configuration file is in ~/.config/chezmoi/chezmoi.toml. You can
edit the file directly but chezmoi provides a command to view and a command
to edit the configuration, chezmoi cat-config
and chezmoi edit-config
respectively. The main benefit of using these commands in not having to remember
where the configuration file is located, or type the full path. You can see the
documentation for the
configuration file for the various options. Some I find useful include
automatically pushing to Git after applying changes and customizing the diff:
Neovim integration
There are a few plugins to integrate chezmoi with nvim. The one I use is
xvzc/chezmoi.vim by virtue of using
LazyVim, which comes with support for chezmoi as one of its [“extra” plugins]
(https://www.lazyvim.org/extras/util/chezmoi). There are some nice things with
this plugin, such as searching the chezmoi-managed configuration using
Telescope (<leader>sz
by default). You can also configure nvim to automatically
treat files in the chezmoi directory as chezmoi files.
Coming next
I’ve just covered some of the basics here. There many more intermediate and advanced things you can do with chezmoi, such as encoding secrets, integrating with password managers and templating. There are also script hooks you can write, for example to install some binary or package before or after some config is modified. I’ll cover some of these in a future post.