Chezmoi is a dotfiles management tool. I wrote about it previously when I almost deleted my dotfiles and was looking for a better way to manage them.
7 months later and I'm happy I chose Chezmoi. I'm managing dotfiles across 3 machines and 2 OS's currently. I have a basic workflow and it seems like a good time to see if there are further benefits to be found. This is a review of my workflow and some notes on how to use the tool more effectively.
I've aliased chezmoi to cm in this article and on all my machines.
Including files or subdirectories from other projects is really interesting and something I didn't realise was possible. It goes a long way to bridging the gap between simple dotfiles management and something more powerful like Ansible.
Next steps (in another 7 months?) would be to use templates and make use of the secrets management capabilities.
Setup
When you
cm inityou create a new git repo in~/.local/share/chezmoi. This is where the source state lives. It's a repo, so you can do all the usual vcs things you'd expect, but cm won't do it for you (by default).cm edit-configopens the configuration file for editing.
Include dotfiles from other projects
Use
.chezmoiexternal.tomlto tell cm to import dotfiles from a different repo. See below for an exampleYou can't include subdirectories from other projects like
oh-my-zshbecause you can't use git submodules (cm uses its own format for the source state).The section heading (the part with square brackets) is the destination path of the object being imported.
typeis "archive" for collections of files (projects) and "file" for individual files. If the url is a tarball then cm will unpack it.The default value for
refreshPeriodis never. Cm caches downloaded archives locally to avoid downloading them every timeapplyis called. To force a refresh, callcm --refresh-externals applyorcm -R apply.When using
Oh My Zsh, make sure you disable auto-updates by settingDISABLE_AUTO_UPDATE="true"in~/.zshrc. Auto updates will cause the~/.oh-my-zshdirectory to drift out of sync with cm's source state. Refresh the downloads (by settingrefreshPeriod) to update Oh My Zsh and its plugins.
Adding files and directories
You add a file to cm with
cm add <file>. This copies the file into the source state but changes the name. If the file you want to track is~/.zshrcthen cm will create a file in the source state calleddot_zshrc.You can
cm add <dir>just like you cancm add <file>. If you copy a directory into the source state, the name of the source state copy will be prepended withdot_, too. The names of the files and dirs inside the directory are not changed.
Which files are tracked, not tracked or ignored
cm managedshows a list of manged filescm unmanagedshows a list of unmanaged files. You can add entire directories withcm add..chezmoiignorecontains a list of files that won't be copied from the source directory to the destination when you runcm apply. This is the opposite of my intuition [documentation].Because
cm applycan change so much stuff, trycm apply --dry-run --verbosefirst..chezmoiignoreis a template, so you can ignore different files on different machines.
Editing tracked files
cm diff will show you what changes would be applied if your ran cm apply from the perspective of the source state (Green ⇒ added to source state).
cm apply will overwrite local changes (after prompting for confirmation) with the copy from the source state.
You can resolve differences if things get messy with cm merge $FILE.
There are 4 ways of editing files:
chezmoi edit $FILE- opens $FILE in the editor.cm editwill open the source state directory. You can also usecm edit --apply $FILEto apply the changes as soon as you close the file.cm cdand then edit the files directly. Thencm applyto apply the changes.cm diffwill show you what changes would be made by runningcm apply, from the perspective of the source state. (Green means added to the source state, red is removed. This is the opposite of my intuition).Edit the file in the home directory and then re-add it using
cm add $FILEorcm re-add(re-add doesn't work with templates). I've created an alias to re-add all files that have been changedcm aa.Edit the file in the home directiry and then merge the changes into the source state with
cm merge $FILE.
Examples
Importing an entire project:
To import Oh My Zsh, the zsh-syntax-highlighting plugin, and powerlevel10k by putting the following in ~/.local/share/chezmoi/.chezmoiexternal.toml:
[".oh-my-zsh"]
type = "archive"
url = "https://github.com/ohmyzsh/ohmyzsh/archive/master.tar.gz"
exact = true
stripComponents = 1
refreshPeriod = "168h"
[".oh-my-zsh/custom/plugins/zsh-syntax-highlighting"]
type = "archive"
url = "https://github.com/zsh-users/zsh-syntax-highlighting/archive/master.tar.gz"
exact = true
stripComponents = 1
refreshPeriod = "168h"
[".oh-my-zsh/custom/themes/powerlevel10k"]
type = "archive"
url = "https://github.com/romkatv/powerlevel10k/archive/v1.15.0.tar.gz"
exact = true
stripComponents = 1
Importing a single file from another project
To import plug.vim from github.com/junegunn/vim-plug into ~/.vim/autoload/plug.vim add this to ~/.local/share/chezmoi/.chezmoiexternals.toml
[".vim/autoload/plug.vim"]
type = "file"
url = "https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim"
refreshPeriod = "168h"
Source
Most of this was taken directly from the documentation.