# 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)