本文へ移動
購読
GUIDE#devtools更新 2026.10.02

chezmoiでdotfilesを管理する:複数マシンへの展開とシークレットの扱い

chezmoiでdotfilesをGitHubに置き、2台目へinit --applyで展開する手順。dot_・private_の規則、テンプレートでの書き分け、age暗号化と秘密情報チェックまで。

level
初級
time
約25分
stack
chezmoi 2.72 / Git / Ubuntu 24.04(macOS・Windowsも可)
author
@ryoma_t
// 前提条件
GitとGitHubの基本操作ができること / 管理したいdotfiles(.bashrcや.gitconfigなど)があること
chezmoiで管理中のドットファイルの差分をapply -vで適用し、statusとmanagedで状態を確認したターミナル
画像:nagoya.dev(実際の画面・実行結果をもとに作成)

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_configprivate_は所有者だけが読める権限~/.ssh(700)と~/.ssh/config(600)
dot_gitconfig.tmpl末尾の.tmplはテンプレート展開後の~/.gitconfig
encrypted_private_credentials.ageageで暗号化されたファイル復号した中身(600)
run_once_before_10-install-packages.shapplyのときに1回だけ実行するスクリプトなし(スクリプトが実行される)

chezmoiのインストールとdotfilesの登録

公式のインストールスクリプトは-bで置き場所を指定できます。chezmoi initでソースのディレクトリとGitリポジトリを作り、管理したいファイルをchezmoi addで登録します。あとでテンプレートにする.gitconfigは、--template付きで登録しておきます。

terminal(1台目)
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
出力(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を作っておきます。

terminal(1台目)
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
exit

2台目では、インストールと初期化を1行で済ませられます。initに渡したリポジトリを~/.local/share/chezmoiへcloneし、--applyでそのまま書き出します。chezmoi init --apply USERのようにGitHubのユーザー名だけを書くとhttps://github.com/USER/dotfiles.gitと解釈され、--sshを足すとSSHのURLになります。非公開リポジトリならSSHのほうが認証の設定が1回で済みます。

terminal(2台目)
sh -c "$(curl -fsLS get.chezmoi.io)" -- -b ~/.local/bin init --apply --ssh USER

2台目(検証ではホームディレクトリを分けて模擬)で書き出された結果は次のとおりで、テンプレートは2台目の設定値で展開され、暗号化したファイルも復号されました。権限も1台目と同じになっています。

出力(2台目)
$ 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]は例なので、自分の名前とアドレスにします。

~/.local/share/chezmoi/dot_gitconfig.tmpl
[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台目とは違う値で展開されます。

~/.local/share/chezmoi/.chezmoi.toml.tmpl(暗号化の設定は次の節で追加)
{{- $email := promptStringOnce . "email" "Git用メールアドレス" -}}
[data]
    email = {{ $email | quote }}
terminal
$ 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専用のパスを書く、と覚えておくと間違えません。

~/.local/share/chezmoi/.chezmoiignore
{{ if ne .chezmoi.os "darwin" }}
.config/karabiner
{{ end }}

シークレットの扱い:age暗号化・パスワードマネージャー・自動チェック

APIトークンのように、リポジトリに置きたいが平文では置けないファイルは、ageで暗号化して登録します。ageは本体に内蔵されているので、別途ageコマンドを入れる必要はありません。鍵を作り、表示された公開鍵(age1で始まる文字列)を設定に書きます。

terminal(1台目)
chezmoi age-keygen --output ~/.config/chezmoi/key.txt
chezmoi edit-config-template     # .chezmoi.toml.tmpl に暗号化の設定を足す(下記)
chezmoi init
chezmoi add --encrypt ~/.config/app/credentials
.chezmoi.toml.tmpl(暗号化の設定を追加したもの)
{{- $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で中断し、ファイルは管理対象に入りませんでした)。

~/.config/chezmoi/chezmoi.toml(追記)
[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を付けると書き換えた差分が表示されます。

出力(2台目で chezmoi update -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 addressCIや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 anychezmoi 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を返すので、定期的なチェックのスクリプトにも組み込めます。

terminal
$ chezmoi status
 M .bashrc
 M .gitconfig
$ chezmoi apply
$ chezmoi status
$ chezmoi verify; echo "rc=$?"
rc=0

1回目の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鍵だけはリポジトリの外で運ぶ、という点を最初に決めておいてください。

次に読む

$ subscribe --weekly
毎週月曜、企業ITとホームラボの要点を5分で。