![](https://i.nostr.build/9NquibWjyPXiz2Q4.png)
@ [ARCHIVED] Jay
2024-05-19 02:25:59
`chezmoi` is a command-line tool that uses `git` to keep your dotfiles in sync across all of your machines. In this guide, I'll show you a simple use case of keeping dotfiles synced between two machines, `machine_A` and `machine_B`. `chezmoi` has many more features that you can explore beyond this as you become more comfortable with the workflow.
## Chezmoi Cheatsheet
![image](https://i.nostr.build/xE9X7.png)
This is a diagram of the various locations `chezmoi` accesses to manage your dotfiles, as well as the relevant commands to move files around. I'll be referencing the locations `home_A`, `chezmoi_A`, `home_B`, `chezmoi_B`, and `repo` shown in this diagram throughout this guide.
## Installation
The first step to using `chezmoi` is installing and initializing it. We will be on `machine_A` to start with. Here, I'll be building the binary from the source code.
First, make sure you have `golang` installed: https://go.dev/doc/install
Then, clone the `chezmoi` repo and use `make` to build it:
```bash
cd /tmp
git clone https://github.com/twpayne/chezmoi.git
cd chezmoi
make build
```
This will create the `chezmoi` binary, which you can then copy any directory in your `PATH`. Here, I'll move it to `~/bin`. If `~/bin` doesn't exist, you have to create it and re-source `~/.profile` to add it to `PATH`.
```bash
mkdir -p ~/bin && source ~/.profile
cp chezmoi ~/bin/chezmoi
```
Now you should be able to run `chezmoi`:
```bash
> chezmoi --version
chezmoi version dev, commit 255846 . . .
```
## Initialization
Now that you've installed `chezmoi`, you have to initialize it. This guide uses the `main` branch for all git operations, and you can change the default branch for git repositories as follows before you initialize `chezmoi`:
```bash
git config --global init.defaultBranch main
```
Then initialize `chezmoi`:
```bash
chezmoi init
```
This creates the `chezmoi` git repository at `~/.local/share/chezmoi`. Based on the diagram above, this is the location corresponding to `chezmoi_A`.
## Adding your first file
Most systems have a `.bashrc` or similar configuration file, so that can be the first dotfile you add to `chezmoi`:
```bash
chezmoi add ~/.bashrc
```
Change into the `chezmoi_A` directory to see the file added to `chezmoi`:
```bash
chezmoi cd
ls
```
You'll see `dot_bashrc` listed. `chezmoi` renames the dots at the start of all of your dotfiles as `'dot_'` so they are not considered hidden. This directory is a git repository as well, but it isn't linked to an online repository yet. You can use a private repository on GitHub or GitLab, or even a self-hosted instance of GitLab. Whatever remote repository you choose to use, follow its instructions to create a new repository called `dotfiles` and add it as `origin` to your local `chezmoi` git repository. Here, I'll create a private GitHub repository and link it using ssh. Then you should be able to see it with:
```bash
> git remote -v
origin git@github.com:wisehodl/dotfiles.git (fetch)
origin git@github.com:wisehodl/dotfiles.git (push)
```
Now commit your first dotfile and push it to the online repo:
```bash
git add dot_bashrc
git commit -m "Added .bashrc"
git push -u origin main
```
Congratulations! You've successfully backed up your first dotfile using `chezmoi`. `chezmoi add` can add individual files as well as directories.
## Adding directories and ignoring files.
`chezmoi` can add whole directories with `chezmoi add` but you may want to ignore certain files if they are auto-generated or contain sensitive information. Say you have a directory you want to add to `chezmoi` that contains some authentication details as well as actual config files, like so:
```bash
/home/wise/.test/
├── .auth
└── .config
```
Here, we want to add `.test` to `chezmoi` but ignore the `.auth` file that contains some login information. First, you'll have to tell `chezmoi` to ignore the `.auth` file using the `.chezmoiignore` file. It works just like `.gitignore` if you're familiar with that.
```bash
echo ".test/.auth" >> .chezmoiignore
```
Now you can add the `.test` directory:
```bash
> chezmoi add ~/.test
chezmoi: warning: ignoring .test/.auth
```
And you'll see that `chezmoi` is purposely ignoring the `.auth` file. If you look at your `chezmoi` directory now, you'll see the `dot_test` directory added with only the config file.
Add these changes to your git repo:
```bash
git add -A
git commit -m "Added .test/"
git push
```
Here, you should start to get a feel for how the workflow for adding files to `chezmoi` typically goes. Before we start modifying files, let's move over to `machine_B` and sync your dotfiles over there.
## Syncing to another machine
For the sake of simplicity, I'll assume that you are syncing your dotfiles to a fresh install of the same Linux distro as `machine_A`. If you have a lot of conflicting dotfiles between `machine_A` and `machine_B`, you'll either need to utilize `git merge` or `chezmoi merge` at your discretion and resolve the conflicts. If certain files do need to be different between the machines, then you'll have to utilize `chezmoi`'s templating capabilities. These situations are beyond the scope of this guide and are left as an exercise for the reader.
On `machine_B` follow the steps above to install and initialize `chezmoi`. Then, add your remote git repository as before, and pull it into the `chezmoi` directory:
```bash
git pull origin main
```
The first time you push from `chezmoi_B`, you may have to run `git push -u origin main` to set the upstream branch and fully set up the remote connection.
Now to review, we've synced up 4 out of the 5 locations in the diagram above: `home_A`, `chezmoi_A`, `repo`, and `chezmoi_B`. Syncing `chezmoi_B` and `home_B` is where things can get complicated if, like I said before, you have a lot of file conflicts. You can check for differences between the source directory, `chezmoi_B` and the destination directory, `home_B` using `chezmoi diff`. There is also the concept of a "target state" in `chezmoi`, but it only becomes relevant if you use templates. In the context of this guide, the source directory is also the target state.
Say, for example, you had some conflicting lines in `~/.bashrc`, `chezmoi diff` would show you the changes that would need to occur to make the destination state, `~/.bashrc`, match the source state, `~/.local/share/chezmoi/dot_bashrc`. There are a few strategies you can use to resolve this conflict:
1. Create a new branch in `chezmoi_B`, add the file from `home_B` with `chezmoi add`, then perform a `git merge` back to main.
1. Use `chezmoi merge ~/.bashrc`, which will take you into a `vimdiff` window to manually change the files to match.
1. Overwrite the source file with the destination file using `chezmoi add ~/.bashrc`
1. Overwrite the destination file with the source file using `chezmoi apply ~/.bashrc`
**[DANGER AHEAD]**
This guide will go with option 4 for every file in `chezmoi_B`:
```bash
# Do not do this unless you want to OVERWRITE files in your
# home directory.
chezmoi apply
```
`chezmoi` will do its best to warn you if you're about to do something dangerous and give you some options on how to proceed.
Doing this, the dotfiles in both `machine_A` and `machine_B` are in sync! But you know that your dotfiles will change and grow over time, so we have to talk about strategies for maintaining this sync.
## Modifying your dotfiles
You have to remain mindful that you're using `chezmoi` to keep your dotfiles in sync, otherwise `machine_A` and `machine_B` can get out of sync pretty easily. `chezmoi` has the `chezmoi edit` command to edit files in the destination state, but I prefer to edit files in either `home_A` or `home_B` and then follow the path in the diagram above from end to end to sync up the whole network.
For example, you can change or add a file from `home_B` and do:
1. `(home_B) $ chezmoi add ~/path/to/.file`
1. `(home_B) $ chezmoi cd`
1. `(chezmoi_B) $ git add -A`
1. `(chezmoi_B) $ git commit -m "Changed ~/path/to/.file"`
1. `(chezmoi_B) $ git push`
1. `(home_A) $ chezmoi cd`
1. `(chezmoi_A) $ git pull`
1. `(chezmoi_A) $ chezmoi apply`
And that will propagate the change across your network. You can also use `chezmoi update` from `home_A` to pull the repo and apply the target state all in one step. The best way to avoid conflicts and headaches is to always push changes you make to you dotfiles as soon as you can and avoid making changes to the same file on two different machines simultaneously, just like with any git repository.
## Conclusion
If you've followed the steps in this guide, you will have learned a workflow to keep the dotfiles between two Linux machines in sync using `chezmoi`. The diagram at the top of the guide should serve as a useful cheatsheet for the most common tasks you'll perform to maintain your dotfiles.
`chezmoi` is a very versatile application, and is capable of managing very complex dotfile setups. Their documentation is very technical and daunting to the new user, but it remains a good resource for doing more complex tasks with `chezmoi`.
- Command Overview: https://www.chezmoi.io/user-guide/command-overview/
- Reference: https://www.chezmoi.io/reference/
---
All the best!
- WiseHODL