# Chezmoi for Linux Distro Hoppers
*A practical, start-to-finish guide to keeping your personal Linux setup reproducible.*
If you enjoy trying Linux distributions, reinstalling a system, or maintaining more than one machine, you eventually meet the same chore: rebuilding the small choices that make a computer feel like yours. Shell settings, terminal profiles, launcher preferences, text-expansion snippets, and application configuration all live in scattered files—usually “dotfiles”—inside your home directory.
[chezmoi](https://www.chezmoi.io/) is a tool for recording the configuration you deliberately want to keep, storing it in a Git repository, and applying it back to a new machine. It does **not** back up an entire home directory or install every application for you. It is a focused, reviewable way to restore your configuration.
> [!tip]
> Start small. A good first repository might contain `.bashrc`, a terminal profile, and a few application settings. Add more only after you understand what each file contains.
## The mental model
chezmoi keeps a **source state**: the version of your configuration that you want machines to have. By default, that source directory is:
```text
~/.local/share/chezmoi
```
Its files are named safely for Git. For example, the live file `~/.bashrc` becomes `~/.local/share/chezmoi/dot_bashrc`. Directories such as `~/.config/albert` become directories under the source state as well.
Think of the workflow as a one-way pipeline that you control:
```text
live configuration in ~/ → chezmoi source state → Git history → private GitHub repo
↓
chezmoi apply on another machine
```
- `chezmoi add` copies an existing live file into the source state.
- `chezmoi edit` changes the source state—the future desired version.
- `chezmoi diff` previews the difference between the source state’s desired result and the live file.
- `chezmoi apply` makes the live file match the desired result.
- Git records and synchronizes the source state; chezmoi does the configuration deployment.
This separation is the reason it works so well for distro hopping: a reinstall can erase the live files, while the Git repository retains the desired configuration.
## Before you begin
### Decide what belongs in the repository
Good candidates are human-maintained settings and portable snippets:
- shell, Git, editor, window-manager, and terminal settings;
- launcher configuration (for example, Albert);
- text-expansion configuration (for example, Espanso);
- terminal profiles (for example, Terminator or Tilda);
- application preferences that do not contain secrets or machine-specific caches.
Usually avoid caches, logs, databases, browser profiles, large generated data, tokens, private keys, and anything whose purpose you cannot explain. A private repository reduces accidental exposure, but it is not encryption and it does not make secrets safe to commit.
> [!warning]
> Read a file before tracking it. Git history is durable: deleting a committed secret from the latest version does not necessarily remove it from earlier commits. Use a password manager or chezmoi’s encryption features for secrets, and rotate any secret committed by mistake.
### Install ChezMoi and Git on Linux Mint
Mint is Ubuntu-based. The distribution packages are convenient, though their version can lag. Either of the following approaches is reasonable:
```bash
# Mint/Ubuntu packages
sudo apt update
sudo apt install chezmoi git
```
Or use the installation method recommended by the [official ChezMoi install page](https://www.chezmoi.io/install/), then verify:
```bash
chezmoi --version
git --version
```
### Install and authenticate GitHub CLI (optional but recommended)
You only need [GitHub CLI](https://cli.github.com/) (`gh`) if you want to create and manage GitHub repositories from the terminal. Follow GitHub CLI’s [Linux installation instructions](https://github.com/cli/cli/blob/trunk/docs/install_linux.md) for the current supported repository setup, then authenticate:
```bash
gh auth login
gh auth status
```
Choose GitHub.com, the preferred protocol (SSH is convenient for private repos), and complete the browser/device login flow. If you use SSH, verify it separately:
```bash
ssh -T
[email protected]
```
## First-time setup on an existing machine
Initialize ChezMoi once:
```bash
chezmoi init
chezmoi source-path
```
The second command should print a path like `~/.local/share/chezmoi`. To work inside that directory in a subshell:
```bash
chezmoi cd
pwd
```
`chezmoi cd` is especially useful before Git commands; `exit` returns to the previous directory.
### Add your first file
```bash
chezmoi add ~/.bashrc
chezmoi managed
```
`managed` lists paths managed by ChezMoi. The add operation copies the current file into the source state; it does not remove the live file.
From here forward, prefer editing the source state:
```bash
chezmoi edit ~/.bashrc
chezmoi diff ~/.bashrc
chezmoi apply -v ~/.bashrc
```
The `-v` flag reports what ChezMoi changes. `-n -v` is an excellent safe preview: it shows the planned action without changing files.
## Adding application configurations
Application config usually lives under `~/.config`. These are illustrative examples; inspect each directory before adding it:
```bash
chezmoi add ~/.config/albert
chezmoi add ~/.config/copyq
chezmoi add ~/.config/espanso
chezmoi add ~/.config/terminator
chezmoi add ~/.config/tilda
```
Adding a directory recursively captures its current contents. That is fast, but it can also capture runtime data you do not want. Review immediately:
```bash
chezmoi managed
chezmoi status
chezmoi diff ~/.config/espanso
```
### Track only the Espanso files you actually want
Suppose you added all of Espanso and then decide its cache, logs, or generated files should stay local. First remove its source-state copy while leaving the live files alone:
```bash
chezmoi forget ~/.config/espanso
```
Then add only the portable files or folders you choose. Common examples might be the user configuration and match definitions (confirm the paths on your installation):
```bash
chezmoi add ~/.config/espanso/config
chezmoi add ~/.config/espanso/match
```
`forget` means “stop managing this path”; it does **not** delete the target in `~/.config`. Confirm the new scope with:
```bash
chezmoi managed | rg 'espanso'
```
## Inspecting changes safely
### `chezmoi status`: what the two columns mean
`chezmoi status` compares three states: (1) what ChezMoi last wrote, (2) what currently exists on disk, and (3) the desired state generated from the source directory.
```bash
chezmoi status
```
The first status character shows the difference from **last-written → actual**. The second shows the difference from **actual → desired**, which is what `chezmoi apply` would do.
| Output | Meaning |
| --- | --- |
| ` M path` | The live file matches the last write, but the desired source version differs; `apply` would modify it. |
| `M path` | The live file changed since ChezMoi last wrote it, but it already matches the desired source version. |
| `MM path` | The live file changed since ChezMoi last wrote it **and** it still differs from desired state; inspect before applying. |
| `A` / `D` | An entry was or will be added/deleted, depending on the column. |
An empty status is normally good: no managed entry needs attention. The precise letters are documented in the [official status reference](https://www.chezmoi.io/reference/commands/status/).
### `chezmoi diff`: see content, not just a letter
```bash
# All managed differences
chezmoi diff
# One application or one file
chezmoi diff ~/.config/albert
chezmoi diff ~/.config/espanso
chezmoi diff ~/.bashrc
```
Read a diff before applying when a program has modified its own config, or before committing a newly added directory. `diff` does not change anything.
### `chezmoi re-add`: adopt intentional live edits
If you edited a managed file directly in `~/` and want that live version to become the new desired source state:
```bash
chezmoi re-add ~/.bashrc
chezmoi re-add ~/.config/terminator
```
This copies the target back into the source state. Follow it with `chezmoi diff` and Git review. Do not use it blindly: it can adopt accidental application changes.
## CopyQ `.dat` files: a deliberate-data example
CopyQ may store settings and history in database-like `.dat` files under `~/.config/copyq`. You may also encounter filenames that look Base64-encoded, such as a string ending in `=`. Base64 is an encoding that lets arbitrary bytes be represented with filename-safe text; it is **not** encryption and does not by itself reveal whether a file is safe to publish.
Discover candidate files without modifying them:
```bash
find ~/.config/copyq -type f -name '*.dat' -print
file ~/.config/copyq/* 2>/dev/null
```
Then make a conscious policy choice:
- track a small preferences database only if it restores useful settings and contains no sensitive clipboard history;
- do **not** track clipboard-history databases by default—clipboard contents can include passwords, private messages, API keys, and copied documents;
- if a file is binary, expect Git diffs to be unhelpful and repository history to grow as it changes.
If you decide a specific `.dat` file is appropriate, add that file, not the entire directory:
```bash
chezmoi add ~/.config/copyq/NAME.dat
```
> [!danger]
> Treat clipboard data as sensitive by default. A private GitHub repository is still shared with anyone granted access, is retained in backups and Git history, and can be exposed by account compromise.
## Git, explained in plain language
Git is the change history for the ChezMoi **source directory**, not the tool that applies dotfiles.
| Git concept | In this workflow |
| --- | --- |
| Working tree | The files currently in `~/.local/share/chezmoi`. |
| Stage (`git add`) | The exact source-state changes selected for the next snapshot. |
| Commit | A named, local snapshot of staged changes. |
| Remote | Another copy of the repository, such as GitHub’s `origin`. |
| Push | Upload local commits to the remote. |
| Pull | Download and integrate remote commits into the local source directory. |
A clean Git status means the source directory has no uncommitted changes; it says nothing by itself about whether the live dotfiles match source. Use both tools:
```bash
chezmoi status # source state versus live home directory
chezmoi cd
git status # source-state files versus Git history
exit
```
## Create a new private GitHub repository from the terminal
This avoids the “two local clones” confusion: the ChezMoi source directory becomes the Git working tree you push. Do this after reviewing the files you plan to publish.
```bash
chezmoi cd
git status
git add .
git commit -m "Initial chezmoi configuration"
gh repo create dotfiles \
--private \
--source=. \
--remote=origin \
--push
git remote -v
exit
```
`gh repo create` with `--source=.` creates a GitHub repository from the existing local repository; `--remote=origin` names the remote; `--push` pushes the current branch. These options are described in the [official GitHub CLI manual](https://cli.github.com/manual/gh_repo_create).
If you created an empty repository on GitHub first instead, you do not need to recreate it. Attach it to the source directory:
```bash
chezmoi cd
git remote add origin
[email protected]:$GITHUB_USERNAME/dotfiles.git
git branch -M main
git push -u origin main
exit
```
If that GitHub repository already contains a README commit, do not force-push over it. Pull and reconcile histories first, or create the remote using `gh repo create` from the local repository as above.
## Normal day-to-day SOP
### When you intentionally change a configuration
```bash
# Prefer source-first edits
chezmoi edit ~/.config/espanso/match/base.yml
chezmoi diff ~/.config/espanso
chezmoi apply -v ~/.config/espanso
# Save the source-state change in Git and sync it
chezmoi cd
git status
git add .
git commit -m "Update Espanso matches"
git push
exit
```
### When an application changed a managed file
```bash
chezmoi status
chezmoi diff ~/.config/terminator
# Only if you want the live version to become canonical
chezmoi re-add ~/.config/terminator
chezmoi cd
git diff
git add .
git commit -m "Update Terminator preferences"
git push
exit
```
### When receiving changes on another existing machine
```bash
chezmoi update -v
```
`update` pulls the source repository and applies the result. For a cautious preview, inspect Git and ChezMoi separately first:
```bash
chezmoi cd
git pull --ff-only
exit
chezmoi diff
chezmoi apply -v
```
## Restore after a fresh install or distro hop
Install ChezMoi and Git first, then clone and apply your repository. For a private repo over SSH:
```bash
chezmoi init --apply
[email protected]:$GITHUB_USERNAME/dotfiles.git
```
Or initialize, preview, then apply—a gentler first restore:
```bash
chezmoi init
[email protected]:$GITHUB_USERNAME/dotfiles.git
chezmoi diff
chezmoi apply -v
```
Afterward, install the applications whose configs you manage (Albert, CopyQ, Espanso, Terminator, Tilda, and so on). ChezMoi restores files; an absent application will not suddenly exist because its configuration was restored.
> [!note]
> Fresh machines have their own hardware, desktop environment, and package versions. Keep configs portable where possible; use ChezMoi templates later for genuine per-machine differences rather than copying one machine’s paths everywhere.
## Verification and troubleshooting
```bash
# Where is ChezMoi’s source state?
chezmoi source-path
# Open a shell there and inspect Git
chezmoi cd
git status
git remote -v
exit
# What does ChezMoi manage?
chezmoi managed
# Is the live home directory aligned with desired state?
chezmoi status
chezmoi diff
# Preview every pending filesystem action, without applying it
chezmoi -n -v apply
# Diagnose common installation/configuration issues
chezmoi doctor
```
If a restored configuration does not take effect, check that the application is installed, that it reads the path you restored, and that it has been restarted. If `chezmoi diff` shows an unexpected overwrite, stop and inspect the source and live file before `apply`.
## Cheat sheet
```bash
# Setup
chezmoi init
chezmoi add ~/PATH/TO/FILE_OR_DIRECTORY
# See and apply desired changes
chezmoi status
chezmoi diff [~/PATH]
chezmoi -n -v apply # safe preview
chezmoi apply -v [~/PATH]
# Manage scope and adopt live changes
chezmoi managed
chezmoi forget ~/PATH # stop managing; keeps the live path
chezmoi re-add ~/PATH # copy intentional live edits into source
chezmoi edit ~/PATH # edit the source-state version
# Git source state
chezmoi source-path
chezmoi cd
git status
git add . && git commit -m "Describe the change" && git push
exit
# Restore / synchronize
chezmoi init --apply
[email protected]:$GITHUB_USERNAME/dotfiles.git
chezmoi update -v
```
## Further reading
- [ChezMoi quick start](https://www.chezmoi.io/quick-start/)
- [ChezMoi command reference](https://www.chezmoi.io/reference/commands/)
- [ChezMoi status reference](https://www.chezmoi.io/reference/commands/status/)
- [GitHub CLI: `gh repo create`](https://cli.github.com/manual/gh_repo_create)
- [GitHub: securing your account and repository access](https://docs.github.com/authentication/keeping-your-account-and-data-secure)