
chezmoiとは、.bashrcや.gitconfigのようなdotfiles(ホームディレクトリにある設定ファイル)をGitリポジトリで管理し、複数のマシンへ同じ設定を展開するためのツールです。シンボリックリンクを張るだけの管理と違い、マシンごとの違いをテンプレートで書き分けられ、秘密情報は暗号化やパスワードマネージャー経由で扱えます。
以下は、執筆時点の最新版chezmoi v2.72.2をUbuntu 24.04のコンテナで動かし、1台目で管理を始めてから、ホームディレクトリを分けて模擬した2台目に展開するまでを確かめた手順です。途中で出たエラーや警告も、実際の文面のまま載せています。
この記事でわかること
- chezmoiの仕組みと、
dot_・private_などファイル名の規則 - dotfilesの登録からGitHubへのpush、2台目での
chezmoi init --applyまで - OSやマシンごとの差分をテンプレートで書き分ける方法
- ageによる暗号化、パスワードマネージャーの利用、
add時の秘密情報チェック chezmoi update・re-addなど日々の運用と、つまずきやすいエラー
chezmoiとは:シンボリックリンク型の管理との違い
dotfilesをGitで管理する昔ながらの方法は、リポジトリにファイルを置いてホームディレクトリからシンボリックリンクを張るやり方です。単純ですが、職場のPCだけメールアドレスを変えたい、macOSだけ設定を足したい、といった差分を1つのファイルで表せず、トークンを含むファイルはそのままリポジトリに入ってしまいます。
このツールは、リポジトリ側の「ソース」(既定は~/.local/share/chezmoi)と、ホームディレクトリ側の実ファイルを分けて扱います。chezmoi applyはソースを読み、テンプレートの展開や暗号の復号をしたうえで、ホームディレクトリに通常のファイルとして書き出します。ソースのファイル名は、書き出すときの名前や属性を表す規則になっています。
| ソース側の名前 | 意味 | 書き出されるもの |
|---|---|---|
dot_bashrc | 先頭のdot_は「.」 | ~/.bashrc |
private_dot_ssh/private_config | private_は所有者だけが読める権限 | ~/.ssh(700)と~/.ssh/config(600) |
dot_gitconfig.tmpl | 末尾の.tmplはテンプレート | 展開後の~/.gitconfig |
encrypted_private_credentials.age | ageで暗号化されたファイル | 復号した中身(600) |
run_once_before_10-install-packages.sh | applyのときに1回だけ実行するスクリプト | なし(スクリプトが実行される) |
chezmoiのインストールとdotfilesの登録
公式のインストールスクリプトは-bで置き場所を指定できます。chezmoi initでソースのディレクトリとGitリポジトリを作り、管理したいファイルをchezmoi addで登録します。あとでテンプレートにする.gitconfigは、--template付きで登録しておきます。
sh -c "$(curl -fsLS get.chezmoi.io)" -- -b ~/.local/bin
chezmoi --version
chezmoi init
chezmoi add ~/.bashrc ~/.ssh/config
chezmoi add --template ~/.gitconfig
chezmoi managed.bashrc
.gitconfig
.ssh
.ssh/configソース側にはdot_bashrc・dot_gitconfig.tmpl・private_dot_ssh/private_configができました。~/.sshが700、~/.ssh/configが600だったため、chezmoiが自動でprivate_を付けています。以後の編集は「ソースを直す→差分を見る→書き出す」の順で、chezmoi edit ~/.bashrc・chezmoi diff・chezmoi apply -vを使います。ホームディレクトリのファイルを直接書き換えてしまった場合は、chezmoi re-add ~/.bashrcでその内容をソースへ取り込みます。
private_が変えるのはファイルの権限だけで、中身は平文のままリポジトリに入ります。GitHubの非公開リポジトリに置く場合でも、トークンや秘密鍵は後述の暗号化かパスワードマネージャーで扱い、~/.ssh/id_ed25519のような秘密鍵をchezmoi addしないでください。
GitHubに置いて2台目に展開する
chezmoi cdはソースのディレクトリでサブシェルを開くコマンドで、ここでは普通のGitリポジトリとして扱えます。検証ではchezmoi initが作ったブランチ名がmasterだったため、GitHubの既定に合わせてmainに変えてからpushしています。先にGitHubで空の非公開リポジトリdotfilesを作っておきます。
chezmoi cd
git remote add origin [email protected]:USER/dotfiles.git
git branch -M main
git add -A && git commit -m "dotfilesを追加"
git push -u origin main
exit2台目では、インストールと初期化を1行で済ませられます。initに渡したリポジトリを~/.local/share/chezmoiへcloneし、--applyでそのまま書き出します。chezmoi init --apply USERのようにGitHubのユーザー名だけを書くとhttps://github.com/USER/dotfiles.gitと解釈され、--sshを足すとSSHのURLになります。非公開リポジトリならSSHのほうが認証の設定が1回で済みます。
sh -c "$(curl -fsLS get.chezmoi.io)" -- -b ~/.local/bin init --apply --ssh USER2台目(検証ではホームディレクトリを分けて模擬)で書き出された結果は次のとおりで、テンプレートは2台目の設定値で展開され、暗号化したファイルも復号されました。権限も1台目と同じになっています。
$ chezmoi managed
.bashrc
.config
.config/app
.config/app/credentials
.gitconfig
.ssh
.ssh/config
$ cat ~/.gitconfig
[user]
name = Ryoma T
email = [email protected]
$ stat -c '%A %n' ~/.ssh ~/.ssh/config ~/.config/app/credentials
drwx------ /home/pc2/.ssh
-rw------- /home/pc2/.ssh/config
-rw------- /home/pc2/.config/app/credentialsテンプレートでマシンごとの差分を書き分ける
テンプレートはGoのtext/templateの書式で、{{ }}の中に変数や条件を書きます。変数には、chezmoiが用意する.chezmoi.os(linux・darwin・windows)や.chezmoi.hostnameに加え、自分で決めた値も使えます。次の.gitconfigは、メールアドレスをマシンごとの設定値にし、macOSのときだけキーチェーンを使う設定を足します。nameのRyoma Tと、出力に出てくる[email protected]は例なので、自分の名前とアドレスにします。
[user]
name = Ryoma T
email = {{ .email }}
{{- if eq .chezmoi.os "darwin" }}
[credential]
helper = osxkeychain
{{- end }}.emailの値は、ソースに置いた.chezmoi.toml.tmplから作られるマシンごとの設定ファイル(~/.config/chezmoi/chezmoi.toml)に入ります。promptStringOnceは、値がまだないときだけchezmoi initの途中で入力を求める関数なので、2台目の初期化で職場のアドレスを答えれば、1台目とは違う値で展開されます。
{{- $email := promptStringOnce . "email" "Git用メールアドレス" -}}
[data]
email = {{ $email | quote }}$ chezmoi init # 設定ファイルを作り直す(ここでメールアドレスを聞かれる)
$ chezmoi execute-template '{{ .chezmoi.os }}/{{ .chezmoi.arch }} {{ .email }}'
linux/amd64 [email protected]
$ chezmoi cat ~/.gitconfig
[user]
name = Ryoma T
email = [email protected]chezmoi execute-templateはテンプレートの断片を試す道具で、chezmoi catは書き出す前の最終形を表示します。特定のOSでだけ使う設定ファイルは、ソースの.chezmoiignoreに「書き出さないもの」を書きます。条件の向きが逆に見えるので、{{ if ne .chezmoi.os "darwin" }}(macOS以外なら)の中にmacOS専用のパスを書く、と覚えておくと間違えません。
{{ if ne .chezmoi.os "darwin" }}
.config/karabiner
{{ end }}シークレットの扱い:age暗号化・パスワードマネージャー・自動チェック
APIトークンのように、リポジトリに置きたいが平文では置けないファイルは、ageで暗号化して登録します。ageは本体に内蔵されているので、別途ageコマンドを入れる必要はありません。鍵を作り、表示された公開鍵(age1で始まる文字列)を設定に書きます。
chezmoi age-keygen --output ~/.config/chezmoi/key.txt
chezmoi edit-config-template # .chezmoi.toml.tmpl に暗号化の設定を足す(下記)
chezmoi init
chezmoi add --encrypt ~/.config/app/credentials{{- $email := promptStringOnce . "email" "Git用メールアドレス" -}}
encryption = "age"
[age]
identity = "~/.config/chezmoi/key.txt"
recipient = "age1で始まる公開鍵をここに書く"
[data]
email = {{ $email | quote }}登録したファイルはソース側でdot_config/app/encrypted_private_credentials.ageになり、中身はageの暗号文です。chezmoi cat ~/.config/app/credentialsやapplyのときだけkey.txtで復号されます。つまりkey.txtがないマシンでは復号できないので、2台目には鍵だけを別の経路で置きます。検証では、鍵を2台目の同じパスにコピーしてからinit --applyし、復号できることを確かめました。鍵そのものはリポジトリに入れず、パスワードマネージャーの安全なメモなどに保管します。
会社でパスワードマネージャーを使っているなら、値をファイルに持たずにテンプレートから読み出す方法もあります。テンプレート関数からは1PasswordのCLI(op)やBitwardenのCLI(bw)を呼び出せ、執筆時点では1PasswordならonepasswordRead、Bitwardenならbitwardenという関数が用意されています。値はapplyのたびにCLIから取得され、リポジトリにもソースにも残りません。代わりに、各マシンでCLIへのサインインが必要です。どちらを採るかは、企業向けパスワードマネージャーの選び方で整理した社内の運用に合わせます。
うっかり防止には、chezmoi addの秘密情報チェックが効きます。暗号化せずに追加するファイルを検査する機能で、GitHubのトークンの形をした文字列を含むファイルを追加すると、chezmoi: /home/pc1/gh.ini:2: Uncovered a GitHub Personal Access Token, potentially leading to unauthorized repository access and sensitive content exposure.という警告が出ました。既定では警告のあとに追加まで進んでしまうため、設定ファイルに次の2行を入れて、検出したら追加を止めるようにしておきます(検証では終了コード1で中断し、ファイルは管理対象に入りませんでした)。
[add]
secrets = "error"chezmoi.tomlはchezmoi initのたびに.chezmoi.toml.tmplから作り直されるため、上の2行を直接書いても次のinitで消えます。常に効かせたい設定は、.chezmoi.toml.tmplの側に書いてください。
日々の運用:update・re-add・自動コミット
別のマシンで変更した設定を取り込むときはchezmoi updateを使います。中身は、ソースでgit pull --autostash --rebaseを実行してからapplyする、という2段の処理です。-vを付けると書き換えた差分が表示されます。
+++ b/.bashrc
@@ -1,3 +1,4 @@
alias ll="ls -alF"
export EDITOR=nvim
alias gs="git status"
+export PAGER=lessホームディレクトリのファイルを直接書き換えたあとにchezmoi applyすると、上書きしてよいか確認されます。どちらを正とするかで対処が分かれ、手元の変更を残すならchezmoi re-add、ソースの内容で上書きするならchezmoi apply --forceです。登録や編集のたびにcommitとpushをするのが面倒なら、設定テンプレートに[git]のautoCommit = trueとautoPush = trueを書くと、chezmoi addやeditのあとで自動的にcommitとpushまで行われます(検証ではaddの直後にmain -> mainのpushが走りました)。
新しいマシンで毎回入れるパッケージがあるなら、run_once_で始まるスクリプトをソースに置きます。検証ではrun_once_before_10-install-packages.shが最初のapplyで1回だけ実行され、2回目のapplyでは動きませんでした。中身を書き換えたときだけ再実行させたい場合はrun_onchange_を使います。
つまずきポイント
| 症状・エラーメッセージ | 原因 | 対処 |
|---|---|---|
.bashrc has changed since chezmoi last wrote it? | ホームディレクトリのファイルを直接編集した | 手元の変更を残すならchezmoi re-add ~/.bashrc、捨てるならchezmoi apply --force |
could not open a new TTY: open /dev/tty: no such device or address | CIやDockerなど端末のない環境で、promptStringOnceの質問に答えられない | chezmoi init --apply --promptString "Git用メールアドレス=自分のメールアドレス" リポジトリのように答えを渡す。キーは変数名ではなく質問文 |
chezmoi: encryption not configured | 設定にencryption = "age"がないままadd --encryptした | .chezmoi.toml.tmplに暗号化の設定を書き、chezmoi initで設定ファイルを作り直す |
error: src refspec main does not match any | chezmoi initが作ったブランチがmasterだった | chezmoi cdしてgit branch -M mainしてからpushする |
chezmoi: warning: config file template has changed, run chezmoi init to regenerate config file | .chezmoi.toml.tmplを編集したが、設定ファイルを作り直していない | chezmoi initを実行する |
動作確認
ソースとホームディレクトリがそろっているかはchezmoi statusとchezmoi verifyで確かめます。statusは差分のあるファイルだけを表示し、何も出なければ一致しています。verifyは一致していれば終了コード0、ずれていれば1を返すので、定期的なチェックのスクリプトにも組み込めます。
$ chezmoi status
M .bashrc
M .gitconfig
$ chezmoi apply
$ chezmoi status
$ chezmoi verify; echo "rc=$?"
rc=01回目のstatusのMは、ソース側の変更がまだ書き出されていない印です。applyは成功すると何も表示しないので、差分を見ながら書き出したいときは-vを付けます。chezmoi doctorを実行すると、使われている設定ファイル・ソースのディレクトリ・Gitの版などをまとめて点検でき、warningの行があればそこから直します。
よくある質問
「Chezmoi」とはどういう意味ですか?
フランス語のchez moi(シェ・モワ、「自分の家で」)に由来する名前で、ホームディレクトリの設定を管理するツールであることに掛けています。日本語では「シェモア」と表記されることが多く、コマンド名は空白なしのchezmoiです。
Chezmoiでgit pullするには?
chezmoi updateを使います。ソースのリポジトリでgit pull --autostash --rebaseを実行し、続けてapplyまで行います。書き出す前に差分を確かめたい場合は、chezmoi git pull -- --autostash --rebaseで取り込むだけにして、chezmoi diffを見てからchezmoi applyします。
chezmoiはWindowsでも使えますか?
使えます。Windowsでは.chezmoi.osがwindowsになるため、同じソースの中でWindowsとLinux・macOSの設定を書き分けられます。PowerShellのプロファイルのようにOSごとに置き場所が違うファイルは、テンプレートと.chezmoiignoreで片方だけを書き出すようにします。
chezmoiで1Passwordの値を使うには?
1PasswordのCLI(op)を入れてサインインし、テンプレートの中でonepasswordRead関数にop://で始まる参照を渡します。値はapplyのたびにCLIから読み出され、リポジトリにもソースにも残りません。関数名と引数の形は執筆時点のもので、変わることがあるため公式ドキュメントで確認してください。
まとめ
chezmoiでは、ソースを直してからdiffとapplyで書き出す流れを守ると、どのマシンの設定が正かで迷いません。マシンごとの差分は.chezmoi.toml.tmplとテンプレート、秘密情報はageかパスワードマネージャーに任せ、[add] secrets = "error"で平文の混入を止めます。age鍵だけはリポジトリの外で運ぶ、という点を最初に決めておいてください。
次に読む
- ssh-keygenでSSH鍵を作る:chezmoiで配る~/.ssh/configと、配ってはいけない秘密鍵の扱い
- Neovim入門:init.luaの書き方とLSP・補完の設定:init.luaとロックファイルをchezmoiで同期する
- tmuxの使い方:.tmux.confをサーバーごとに少しずつ変える例