こんにちは、ナナオです。
今回はchezmoiというツールでdotfileを管理する基盤を作っていこうと思います。
chezmoiとは
WSLとかlinuxとかMacとか触ってると、.sshとか.zshrcとかいろいろ出来上がると思います。
chezmoiはそんなdotfileたちを管理するためのツールです。
インストール&ファイルを管理対象に含める
miseを使ってインストールします。
mise use -g chezmoi
brewでもインストールできます。
brew install chezmoi
インストールはこれで完了です。
コマンドを確認してみましょう。
❯ chezmoi
Manage your dotfiles across multiple diverse machines, securely
Usage:
chezmoi [command]
Documentation commands:
doctor Check your system for potential problems
help Print help about a command
license Print license
Daily commands:
add Add an existing file, directory, or symlink to the source state
apply Update the destination directory to match the target state
chattr Change the attributes of a target in the source state
diff Print the diff between the target state and the destination state
edit Edit the source state of a target
forget Remove a target from the source state
init Setup the source directory and update the destination directory to match the target state
merge Perform a three-way merge between the destination state, the source state, and the target state
merge-all Perform a three-way merge for each modified file
re-add Re-add modified files
status Show the status of targets
update Pull and apply any changes
Template commands:
cat Print the target contents of a file, script, or symlink
data Print the template data
execute-template Execute the given template(s)
Advanced commands:
cd Launch a shell in the source directory
edit-config Edit the configuration file
edit-config-template Edit the configuration file template
generate Generate a file for use with chezmoi
git Run git in the source directory
ignored Print ignored targets
managed List the managed entries in the destination directory
unmanaged List the unmanaged files in the destination directory
verify Exit with success if the destination state matches the target state, fail otherwise
Encryption commands:
age Interact with age
age-keygen Generate an age identity or convert an age identity to an age recipient
decrypt Decrypt file or standard input
edit-encrypted Edit an encrypted file
encrypt Encrypt file or standard input
Remote commands:
docker Use your dotfiles in a Docker container
ssh SSH to a host and initialize dotfiles
Migration commands:
archive Generate a tar archive of the target state
destroy Permanently delete an entry from the source state, the destination directory, and the state
import Import an archive into the source state
purge Purge chezmoi's configuration and data
upgrade Upgrade chezmoi to the latest released version
Internal commands:
cat-config Print the configuration file
completion Generate shell completion code
dump Generate a dump of the target state
dump-config Dump the configuration values
secret Interact with a secret manager
source-path Print the source path of a target
state Manipulate the persistent state
target-path Print the target path of a source path
Flags:
--age-recipient string Override age recipient
--age-recipient-file string Override age recipient
--cache path Set cache directory (default /home/banan/.cache/chezmoi)
--color bool|auto Colorize output (default auto)
-c, --config path Set config file
--config-format <none>|json|toml|yaml Set config file format
--debug Include debug information in output
-D, --destination path Set destination directory (default /home/banan)
-n, --dry-run Do not make any modifications to the destination directory
--force Make all changes without prompting
-h, --help help for chezmoi
--interactive Prompt for all changes
-k, --keep-going Keep going as far as possible after an error
--less-interactive Prompt for changed or pre-existing targets
--mode file|symlink Mode (default file)
--no-pager Do not use the pager
--no-tty Do not attempt to get a TTY for prompts
-o, --output path Write output to path instead of stdout
--override-data string Override data
--override-data-file path Override data with file
--persistent-state path Set persistent state file
--progress bool|auto Display progress bars (default auto)
-R, --refresh-externals always|auto|never[=always] Refresh external cache (default auto)
-S, --source path Set source directory (default /home/banan/.local/share/chezmoi)
--source-path Specify targets by source path
--use-builtin-age bool|auto Use builtin age (default auto)
--use-builtin-diff Use builtin diff
--use-builtin-git bool|auto Use builtin git (default auto)
-v, --verbose Make output more verbose
--version version for chezmoi
-W, --working-tree path Set working tree directory
Use "chezmoi [command] --help" for more information about a command.
なにやらいろいろ出力されました。
早速dotfileを管理してみましょう。
以下のコマンドを実行して初期化します。
❯ chezmoi init
chezmoi: mkdir /run/user/1000/: permission denied
あら、エラーが出てしましました。
どうやらWSL固有の問題っぽいです。
以下のようにXDG_RUNTIME_DIR環境変数の指定を空にして実行します。
XDG_RUNTIME_DIR="" chezmoi init
実行に成功しました。
毎回設定するのは面倒なので、miseで環境変数として登録しておきましょう。
mise set -g XDG_RUNTIME_DIR=""
そしたら早速dotファイルを追加してみます。
chezmoi add ~/.tigrc
追加したファイルを管理対象から外すにはforgetコマンドを使用します。
chezmoi forget ~/.tigrc
今回はこの状態で変更を適用しましょう。
ここでいう変更の適用とは、chezmoiで管理しているファイル(先ほどの例だと.tigrc)の中身を、chezmoiのディレクトリ内のファイル(dot_tigrcという名前で保存されている)と同期させるという意味です。
chezmoi apply
一通りの操作はこれで完了です。
chezmoiの実態をgithubで管理する
さて、先ほどの手順でローカル上のchezmoiのディレクトリに、管理したいdotfileを含めることができました。
あとはこれをgithub上に上げれば、ほかのPCからも参照可能になります。
ということで上げていきましょう。
chezmoi cd # chezmoiのディレクトリに移動
gh repo create # リポジトリを作成
git branch -m main # ブランチ名を変更
# コミットとプッシュ
git add --all
git commit -m "first commit"
git push origin main
ghコマンド使うと楽に作成できますね。
もう一台のPCでchezmoiを使う
では、環境を変えてもう一台でもchezmoiをセットアップしていきます。
インストールは同じくmiseを使って行いました。
initコマンドの実行時に、先ほど作成したGithubのリポジトリを参照するようにします。
chezmoi init git@github.com:satodaiki/chezmoi-dotfiles.git
あとはupdateをすれば、先ほどの設定が適用されます!
chezmoi update
ファイルが競合する場合
.zshrcといったファイルは個別の開発環境ごとに記載内容がブレることがあります。
そういった場合はmergeコマンドを使って解決するか、templateを使います。
今回はmergeを使った方法を試します。
まずはそれぞれの環境で違う内容を記載したdotfile(.zshrc)を追加します。
chezmoi add ~/.zshrc
プッシュを行います。
chezmoi git commit -- -m "Add zshrc"
chezmoi git push origin main
次に別PCで作業します。
ここでupdateをしてしまうと、別PCの.zshrcの内容が消失してしまうので気を付けましょう。
(私はやらかしてしまいました、実行前にcatで表示しておいたおかげで助かりましたが。。)
既存のファイルがある場合は必ず以下のようにバックアップを取ってからupdateを実行してください。
cp ~/.zshrc ~/.zshrc.bak
updateを実行します。
chezmoi update
こうすると~/.zshrcが上書きされます。
一度~/.zshrc.bakの内容を~/.zshrcに書き換えます。
この状態でdiffを見てみましょう。
❯ chezmoi diff
diff --git a/.zshrc b/.zshrc
index b7188ab14736522d260ea61aefd778622270fa5a..07241a3d3cd3add88186694ae8a33022eb87c3f1 100644
--- a/.zshrc
+++ b/.zshrc
@@ -1,39 +1,33 @@
-# homebrewの設定
+# brewの設定
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
-# miseのアクティベート
+# miseの設定
eval "$(mise activate zsh)"
# znapの設定
+# https://neer-engineer.com/525df03075fc272fc364d71a58b9f5a6/
source ~/.znap/znap.zsh
-
-# リポジトリの設定
-# これがないとホームディレクトリ上にプラグインなどのリポジトリフォルダが出来上がってしまう
zstyle ':znap:*' repos-dir ~/.znap/repos
-
-# プロンプトの設定
-# ohmyzshのテーマを使いたい場合は以下のように実装する
-# znap prompt ohmyzsh/ohmyzsh random
znap prompt sindresorhus/pure
-
-# ohmyzsh関連の設定
-znap source ohmyzsh/ohmyzsh plugins/git
-znap source ohmyzsh/ohmyzsh plugins/docker
-znap source ohmyzsh/ohmyzsh plugins/brew
-
-# プラグインの設定
-znap install zsh-users/zsh-completions
znap source marlonrichert/zsh-autocomplete
znap source zsh-users/zsh-autosuggestions
znap source zsh-users/zsh-syntax-highlighting
+znap source zsh-users/zsh-completions
znap source hlissner/zsh-autopair
-znap source marlonrichert/zsh-edit
# kubectlの設定
source <(kubectl completion zsh)
+znap source ohmyzsh/ohmyzsh plugins/kubectl
+
+# terraformの設定
+autoload -U +X bashcompinit && bashcompinit
+complete -o nospace -C /home/linuxbrew/.linuxbrew/Cellar/terraform/1.14.3/bin/terraform terraform
+znap source ohmyzsh/ohmyzsh plugins/terraform
-# opensslの設定
-export PATH="/home/linuxbrew/.linuxbrew/opt/openssl@1.1/bin:$PATH"
+# awsの設定
+autoload bashcompinit && bashcompinit
+autoload -Uz compinit && compinit
+complete -C '/home/linuxbrew/.linuxbrew/bin/aws_completer' aws
-# OpenCodeの設定
-source <(opencode completion zsh)
+# giboの設定
+source <(gibo completion zsh)
うーん、かなりいろいろ違いますね。
この状態でmergeコマンドを実行すると、vimdiffが起動します。
chezmoi merge ~/.zshrc
…が、vimdiffは難しいので手動でマージします。
一旦chezmoiのdot_zshrcと同期しましょう。
chezmoi re-add ~/.zshrc
マージ作業が終わったらリモートリポジトリにプッシュします。
chezmoi git add -- --all
chezmoi git commit -- -m "Merge zshrc"
chezmoi git push
ファイル競合は解決できました!
(スマートな方法ではないけど。。)
感想
簡単にdotfileを管理することができました。
ただファイル競合に関してはもっとスマートな方法で解決したかった。。
追記
別PCからchezmoi updateをしようとしたところ、以下のようなエラーになりました。
❯ chezmoi update
There is no tracking information for the current branch.
Please specify which branch you want to rebase against.
See git-pull(1) for details.
git pull <remote> <branch>
If you wish to set tracking information for this branch you can do so with:
git branch --set-upstream-to=origin/<branch> main
chezmoi: git: exit status 1
おそらく内部的にgit pullコマンドが走っているからでしょう。
エラー出力にもある通り、以下のようなコマンドを打てば解決します。
git branch --set-upstream-to=origin/main main