关于 chezmoi-management
面向维护 mizchi 个人配置的 chezmoi 操作指南,说明与 Nix home-manager、APM 的职责边界,并涵盖日常同步、初始化和故障处理。
主要功能
- 01对照 source 与目标文件检查差异
- 02在配置源与目标间同步文件
- 03使用 Go 模板管理配置
- 04区分 home-manager、chezmoi 与 APM 管理范围
- 05通过推送钩子运行密钥扫描
适用场景
- 01在新机器上初始化个人配置环境
- 02将手动修改的配置纳入 chezmoi
- 03排查 apply 后的配置冲突
- 04避免 APM 技能与 chezmoi 文件覆盖
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mizchi/ skills --skill chezmoi-management安装后在 Claude Code 中输入/chezmoi-management确认已加载。
附带文件README.mdSKILL-ja.md
详细介绍
chezmoi 管理(mizchi 个人)
个人 dotfiles 操作笔记。官方 chezmoi 文档已经足够,因此本文只关注我自己的环境中具体如何运作。
基础环境
| 项目 | 值 |
|---|---|
| 源目录 | ~/.local/share/chezmoi/ |
| 远程仓库 | https://github.com/mizchi/chezmoi-dotfiles.git |
| 分支 | main |
软件包 / programs.* | 通过 dot_config/home-manager/flake.nix 使用 nix home-manager(独立的 home-manager 模式或集成的 nix-darwin 模式) |
| pre-push | pkfire(Taskfile.pkl + pkf hooks install)+ secretlint |
| 应用后钩子 | run_after_apm-install.sh → apm install --global --target claude |
与 nix home-manager 的职责划分
此仓库与 home-manager 并行运行,两者互不包含:
- home-manager 管理:CLI 软件包(
home.packages)、programs.*封装器(git / direnv / zsh / 等),以及通过 Nix 派生构建安装的工具(例如pkfire、pkl、actionlint、awscli2、pkgs.go)。编辑dot_config/home-manager/common.nix,然后运行darwin-rebuild switch --flake .#macos(或home-manager switch)。 - chezmoi 管理:
programs.*无法配置的 dotfile 内容,例如~/.claude/、~/.codex/、~/.apm/、临时添加的~/.config/<editor-or-shell>/、~/.zshrc,以及保留模板的路径。 - APM 管理:
~/.claude/skills/<name>/下的公开 Claude Code 技能。.chezmoiignore会列出每个由 APM 管理的技能,确保 chezmoi 不会在apm install -g后重新部署并覆盖它们。
规则:如果 home-manager 中存在某个工具的 programs.* 封装器,就在那里进行配置,不要再通过 chezmoi 暂存对应的 dotfile。混用会导致两个事实来源相互冲突,表现为“我编辑了文件,但更改总是被还原”。
目录布局速查
~/.local/share/chezmoi/
├── dot_apm/ → ~/.apm/ (APM config)
├── dot_claude/ → ~/.claude/ (Claude Code)
│ ├── CLAUDE.md.tmpl
│ ├── settings.json.tmpl
│ ├── rules/
│ └── skills/ → ~/.claude/skills/ (self-authored skills)
├── dot_codex/ → ~/.codex/
├── dot_config/ → ~/.config/ (helix, mise, sheldon, starship, zellij, zsh, home-manager)
│ └── home-manager/ → ~/.config/home-manager/ (flake.nix / common.nix / darwin.nix — Nix-evaluated; chezmoi only stages the files, Nix does the actual install)
├── dot_zshrc → ~/.zshrc
├── run_once_before_install-brew.sh (bootstrap: clone Homebrew prefix to ~/brew before nix-darwin first activation)
└── run_after_apm-install.sh (every apply: apm install --global --target claude)
文件名前缀含义
| 前缀 | 含义 | 示例 |
|---|---|---|
dot_ | 前置 . | dot_zshrc → .zshrc |
executable_ | +x 权限 | executable_setup.sh → setup.sh(755) |
private_ | 0600 权限 | private_key → key(600) |
.tmpl | Go 模板 | CLAUDE.md.tmpl → CLAUDE.md,并展开主机名等信息。 |
run_once_ | 仅首次运行 | run_once_install_brew.sh |
run_after_ | 每次 apply 后运行 | run_after_apm-install.sh |
日常流程
(1) 检查差异
chezmoi diff # diff between source and dest
chezmoi status # rough status (MM/M /?? etc.)
chezmoi diff 的方向理解:输出顺序为 - dest / + target(遵循 git diff 中旧版本为当前状态、新版本为 apply 后状态的惯例)。
-行 = dest(当前实际文件)中的内容 — apply 会将其移除+行 = target(展开 source.tmpl 后的预期状态)中的内容 — apply 会将其添加chezmoi apply会将 dest 调整为与 target 一致(source → dest)
不确定时,最快的确认方法是分别查看 cat <source> 和 cat <dest>。
chezmoi status 的列为 [source][dest]:
M= 已修改,A= 已添加,D= 已删除,?= 未跟踪(不在 source 中)MM→ 两边都有更改(需要将手动编辑的 dest 合并到 source)M→ source 未变,但 dest 已修改(意外更改)DA→ source 中标记为已删除,但 dest 中仍存在(例如node_modules/等垃圾文件)
(2) 编辑了 dest(实际文件)→ 合并到 source
chezmoi add ~/.zshrc # add a new file
chezmoi re-add # bulk-reflect changes from managed dest into source
chezmoi re-add ~/.claude/CLAUDE.md # individual
(3) 编辑了 source(仓库侧)→ 应用到 dest
chezmoi diff # look first
chezmoi apply # all
chezmoi apply ~/.claude/CLAUDE.md # individual
chezmoi apply --verbose # show what it's doing
(4) 在编辑器中打开 source
chezmoi edit ~/.zshrc # open the source side (whether to apply after closing the editor is controlled by the -a flag)
chezmoi edit -a ~/.zshrc # also run apply after editing
chezmoi cd # cd to source dir
初始化新机器
安装顺序为 nix → chezmoi → apm。brew 前缀由 chezmoi 的 run_once_before_install-brew.sh 引导,因此 nix-darwin 的 homebrew 模块首次激活时即可引用 ~/brew。
# 1. Install Nix (Determinate Systems installer recommended).
curl -fsSL https://install.determinate.systems/nix | sh -s -- install
# 2. Bootstrap chezmoi (clones repo + applies; the brew script runs once here).
chezmoi init https://github.com/mizchi/chezmoi-dotfiles.git --apply
# 3. Switch home-manager / nix-darwin (installs pkfire, pkl, awscli2, …).
nix run nix-darwin -- switch --flake ~/.config/home-manager#macos
# (or for standalone HM without system-layer changes:
# nix run home-manager/master -- switch --flake ~/.config/home-manager#macos)
# 4. Arm the pre-push gate on this repo's source.
cd $(chezmoi source-path)
pkf hooks install # writes .git/hooks/pre-push (secretlint over outgoing diff)
# 5. apm install -g already fired via run_after_apm-install.sh during step 2.
# To pick up upstream updates later: apm install -g --update
技能添加流程(我的个人惯例)
- 在
~/.claude/skills/<name>/中开发并验证(对于 nix-setup,需确保nix build通过) - 运行
chezmoi add ~/.claude/skills/<name>,将其同步到源目录- 带有
+x的脚本会自动添加executable_前缀
- 带有
- 运行
cd ~/.local/share/chezmoi && git status,确认已添加的文件 - 运行
git add dot_claude/skills/<name>/,然后提交并执行git push origin main
如果你编辑的是现有技能
chezmoi add 和 chezmoi re-add 都会覆盖内容。实际上,re-add 往往产生的无关差异更少:
chezmoi re-add ~/.claude/skills/nix-setup/SKILL.md
APM 与 chezmoi 的边界
~/.claude/skills/ 是两个系统的混合目录:
| 类型 | 添加方式 | 管理位置 |
|---|---|---|
| APM 管理(外部仓库) | apply 后通过 apm install --global 获取 | ~/.local/share/chezmoi/dot_apm/apm.yml |
| chezmoi 管理(自行编写) | 通过 chezmoi add 复制到源目录 | ~/.local/share/chezmoi/dot_claude/skills/<name>/ |
当前通过 APM 安装的技能(摘自 dot_apm/apm.yml):
moonbitlang/moonbit-agent-guide/*(moonbit-agent-guide、moonbit-refactoring、moonbit-c-binding)mizchi/moonbit-practice/skills/moonbit-practicemizchi/flaker/skills/flaker-setupast-grep/agent-skill/ast-grepmizchi/tui.mbt/skills/tuimbt-practice
决策标准:
- 公开发布/可能在其他仓库中使用 → 放入上游仓库并通过 APM 注册
- 仅在我自己的环境中使用的运维说明/实验性技能 → 由 chezmoi 管理
如果两个位置都存在同名目录,APM 可能会在安装时覆盖该目录,因此请留意名称冲突。
在将新技能添加到 chezmoi 前,检查是否与 APM 名称冲突:
# Check whether the same name exists on the APM side
grep "<skill-name>" ~/.local/share/chezmoi/dot_apm/apm.yml
# or
chezmoi cd && grep -r "<skill-name>" dot_apm/
编辑 tmpl 文件
CLAUDE.md.tmpl 和 settings.json.tmpl 是 Go 模板:
chezmoi edit ~/.claude/CLAUDE.md # opens the source-side .tmpl, not the real file
chezmoi execute-template < foo.tmpl # manually check the expansion result
chezmoi data # list data available for expansion (hostname, OS, etc.)
模板变量示例:{{ .chezmoi.os }}、{{ .chezmoi.hostname }}
注意:对由 .tmpl 管理的文件(CLAUDE.md.tmpl、settings.json.tmpl 等)运行 chezmoi re-add,会用展开后的目标文件内容覆盖源文件中的 .tmpl 语法。要更新 .tmpl 文件,请使用 chezmoi edit(它会自动打开 .tmpl 文件),或直接编辑 ~/.local/share/chezmoi/dot_claude/CLAUDE.md.tmpl。
重新添加前的检查:始终使用 chezmoi source-path 检查目标文件是否由 .tmpl 管理:
chezmoi source-path ~/.claude/CLAUDE.md
# → /Users/mz/.local/share/chezmoi/dot_claude/CLAUDE.md.tmpl
# If it ends in .tmpl, don't re-add — edit manually. If not .tmpl, re-add is OK
要更改 tmpl 变量的默认值时
不要将 tmpl 本身改写为硬编码值,而应将变量放入 ~/.config/chezmoi/chezmoi.toml 的 [data] 部分:
[data]
claude_default_mode = "auto"
github_username = "mizchi"
保留 {{ .claude_default_mode | default "acceptEdits" }} 这类 tmpl 结构原样不动,并通过 [data] 按主机切换值,会更加灵活(也为在不同机器上使用不同设置留出空间)。
pre-push(pkfire + secretlint)
secretlint 会通过 pkfire 在 git push 时运行(Taskfile.pkl → pkf hooks install → .git/hooks/pre-push),检查即将推送的差异范围。包含 API 密钥或令牌的差异会被拒绝。
在全新检出后,运行 pkf hooks install 重新启用钩子。紧急情况下可绕过:git push --no-verify。
常见误报:
- 示例 sha256/十六进制字符串(长度可能类似 AWS 密钥/GitHub 令牌而触发检查)
.envrc注释中的示例值
解决方法:
# If it really is a false positive, exclude the rule in .secretlintrc.json
# If the detection is correct, fix the line and git add ... && git commit
.secretlintrc.json 中的排除语法(摘录):
{
"rules": [
{
"id": "@secretlint/secretlint-rule-preset-recommend",
"options": {
"allows": [
"/sha256-[a-f0-9]{64}/",
"fake-token-for-example",
"skill-examples/*"
]
}
}
]
}
allows 接受正则表达式(用 /.../ 包围)或字面字符串匹配。可以通过 disabledRules + includes/excludes 按文件排除。
不要使用 --no-verify(这会使检查失去意义)。
故障排除
chezmoi status 显示大量 DA(node_modules/ 等)
追加到 .chezmoiignore:
node_modules
**/.DS_Store
源文件与目标文件冲突
chezmoi merge ~/.zshrc # 3-way merge (vimdiff-style)
chezmoi forget ~/.something # remove from source (keep dest)
chezmoi destroy ~/.something # remove both (destructive)
chezmoi merge 后端在 ~/.config/chezmoi/chezmoi.toml 的 [merge] 部分中配置:
[merge]
command = "nvim"
args = ["-d", "{{ .Destination }}", "{{ .Source }}", "{{ .Target }}"]
如果未设置,chezmoi 会查询 git config merge.tool。如果两者都未设置,则会回退到 vimdiff。
Apply 弄坏了东西 → 回滚到之前的修订版本
chezmoi 本身没有撤销功能。通过源端的 git 回滚:
chezmoi cd
git log --oneline -5
git reset --hard <rev>
cd -
chezmoi apply
哪些文件受管理
chezmoi managed # list of managed files
chezmoi unmanaged ~/ # unmanaged files
chezmoi managed ~/.claude # filter by path
apply 速度很慢
run_after_apm-install.sh 中的 apm install 每次都会运行。如果不需要更新 skill,可在 apply 时通过环境变量跳过:
SKIP_APM=1 chezmoi apply # only if the script supports it (otherwise ignored)
如果不支持,请忽略。
命令参考速查表
chezmoi diff # diff
chezmoi status # status
chezmoi apply [-v] # apply
chezmoi add <path> # take in a new file
chezmoi re-add [<path>] # re-take an existing file
chezmoi edit [-a] <path> # edit source (-a applies immediately after)
chezmoi merge <path> # 3-way merge for conflicts
chezmoi forget <path> # drop from source
chezmoi managed [<path>] # list managed files
chezmoi unmanaged <path> # unmanaged files
chezmoi cd # cd to source-path
chezmoi source-path # show source directory
chezmoi execute-template < # test template expansion
chezmoi data # list variables usable in templates
chezmoi doctor # setup diagnosis