关于 drupal-config-reconcile
drupal-config-reconcile 是用于协调 Drupal 跟踪配置与部署环境配置差异的引导式工作流。它逐项审查差异,帮助团队选择导入、导出或跳过,并将写入限制在本地文件。
主要功能
- 01比较跟踪配置与参考环境
- 02将差异归为导入、导出或跳过
- 03使用 config:get 获取单项配置
- 04仅将导出内容写入本地文件
- 05通过导入转换器验证结果
适用场景
- 01部署前协调配置漂移
- 02将环境中创建的配置纳入版本控制
- 03导入前审查配置 UUID 差异
- 04确认导出的配置能否在部署中保留
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ grasmash/ drupal-claude-skills --skill drupal-config-reconcile安装后在 Claude Code 中输入/drupal-config-reconcile确认已加载。
详细介绍
Drupal 配置协调
一个引导式工作流,用于解决已跟踪配置(config/default 以及任何拆分目录)与已部署环境中的活动配置之间的差异。大多数团队都掌握了相关操作(config:status、cim、cex),但没有一套严谨的方法逐项检查差异并决定哪一方为准。本工作流就是这套方法。
核心决策:导入、导出或跳过
对于每个存在差异的配置项,以下三种情况恰有一种成立,你需要选择一个方向:
- 导入 = 磁盘 → 数据库。 已跟踪文件是唯一事实来源;它会在下次代码部署并导入配置时部署到环境中。不更改文件——保留 Git 中的内容。
- 导出 = 数据库 → 磁盘。 以环境中的值为准;将环境中的配置写入已跟踪文件(如果环境中没有该配置,则执行
git rm删除文件)。 - 跳过。 保留未解决的差异并继续(对于仅涉及
_core的差异,这是正确的选择)。
切勿对生产环境执行配置写入操作。 此工作流只会从参考环境中读取,只会向本地文件写入。它绝不会写入任何远程数据库。
远程 CLI——不依赖主机平台
以下示例使用 Pantheon 的 Terminus。任何主机平台上的工作流都相同——只需替换为你所用平台的远程 Drush 命令。如果平台提供 Drush 站点别名,通用的 drush @<alias> <cmd> 形式在任何平台上都适用,也是最简单的基准方案。
| 任务 | Acquia(acli) | Pantheon(Terminus) | Platform.sh / Upsun | Lagoon(amazee.io) | 通用(Drush 别名) |
|---|---|---|---|---|---|
| 远程 Drush | acli remote:drush -- <cmd> | terminus drush <site>.<env> -- <cmd> | platform drush -e <env> -- <cmd>(Upsun:upsun drush …) | lagoon ssh -p <project> -e <env> -C "drush <cmd>" | drush @<alias> <cmd> |
| 从生产环境刷新非生产数据库 | 云端 UI 复制数据库 / acli api:environments:database-copy | terminus env:clone-content <site>.live <env> --db-only | platform sync data(Upsun:upsun sync data) | drush sql:sync 或 Lagoon 发布后的任务 | drush sql:sync @<prod> @<env> |
| 将数据库拉取到本地 | acli pull:db | (drush sql:sync) | platform db:dump | lagoon ssh … -C "drush sql:dump" | drush sql:sync @<env> @self |
| 获取 Drush 别名 | acli remote:aliases:download | terminus aliases | Platform.sh 提供的 @platform.<env> | drush sa(Lagoon 提供) | drush/sites/ 中的别名 |
每个平台只需认证/关联一次: Acquia
acli auth:login+acli link;Pantheonterminus auth:login;Platform.sh/Upsunplatform login/upsun login;Lagoonlagoon login。切勿对任何平台执行面向生产环境的写入/克隆操作。
工作流
1. 选择参考环境(切勿使用 live/prod)
使用非生产环境作为生产环境的替代参考(例如 Pantheon dev/test,或 CI/预发布别名)。拒绝将实时生产环境作为目标——对生产环境执行配置写入会导致团队破坏生产配置。
2. 确保参考数据库为最新
只有当参考环境反映了当前生产环境的状态时,差异才有意义。如果环境数据库已过时(通常超过 24 小时),请先从生产环境刷新。在 Pantheon 上:
terminus env:clone-content <site>.live <env> --db-only -y # Pantheon; see the table above for acli / platform / upsun / lagoon
克隆会修改共享环境,而且需要几分钟——请先征得用户确认;切勿静默执行。(注意:大多数平台无法可靠判断环境上次刷新的时间——terminus backup:list 报告的是备份的时间,而不是从生产环境克隆的时间。只能将其视为参考信息,并向用户确认。)
3. 在参考环境上获取差异(而非本地)
在参考环境上运行 config:status,以便 Drupal 正确应用配置拆分和 config_exclude_modules —— 在本地运行会因仅供开发环境使用的模块(devel、views_ui、生产环境拆分等)而产生误报:
terminus drush <site>.<env> -- config:status --format=json # or your platform's remote-drush form (see table)
你会看到以下状态:
Only in DB—— 存在于环境的数据库中,但不在受跟踪的配置中。Only in sync—— 存在于受跟踪的配置中,但不在环境的数据库中。Different—— 两边都存在,但内容不同。
列表为空 → “已同步,无需协调” → 停止。
4. 使用 config:get 获取环境中每个项目的值(而非完整导出)
不要使用 config:export --destination + scp —— config_split 通常会因尝试在临时目标目录下创建相对拆分目录而失败,而且不同 Terminus 版本对 SSH 命令的发现方式也不稳定。按需逐项获取:
terminus drush <site>.<env> -- config:get <name> --format=yaml > /tmp/ref-<name>.yml # or your platform's remote-drush form
config:get --format=yaml 输出 Drupal 导出的确切文件格式(没有 _core 键)—— 与受跟踪的同类文件逐字节一致。
注意: config:get 会额外追加一个尾随换行符。Drupal 的 phpcs(Drupal.Files.EndFileNewline.TooMany)不允许文件末尾有两个换行符,且提交前钩子会阻止提交。写入文件时,请规范化为恰好一个尾随换行符:
printf '%s\n' "$(cat /tmp/ref-<name>.yml)" > config/default/<name>.yml
5. 逐项处理
创建一个待办列表(每个配置名称一项),以便查看进度。按以下顺序处理:先 Only in DB,再 Different,最后 Only in sync;每项按以下步骤处理:
- 定位本地文件。 通常位于
config/default/<name>.yml。如果该文件不存在,请先检查拆分目录(config/prod/、config/local/、config/envs/…),再判断文件是否缺失——由拆分管理的项目位于config/default之外,必须写回同一个拆分目录。 - 显示内容差异(左侧标记为本地/磁盘,右侧标记为环境/数据库):
Different:diff -u config/default/<name>.yml /tmp/ref-<name>.ymlOnly in DB:本地文件不存在 → 显示环境中的完整内容。Only in sync:环境中不存在 → 显示本地文件的完整内容。
- 建议处理方向并说明原因:
Only in DB→ 导出。 在环境中通过界面或更新钩子创建、应纳入 git 的配置(消息模板、视图显示等)。Only in sync→ 导入。 代码中新增的配置尚未部署;保留它并让它随部署生效。Different:- 只有
_core不同 → 跳过(无害的环境产物;不要无谓改动文件)。 uuid不同 → 导出。 这不是无害差异:当同步文件的uuid与当前生效的 UUID 不同时,下一次导入时StorageComparer::addChangelistUpdate()会将该配置实体标记为重新创建(先删除,再创建)。对于字段存储,这会删除该字段的数据。必须以环境中的 UUID 为准。- 环境中有明显属于有意更改的值 → 导出。
- 本地文件中有明显属于有意的代码更改 → 导入。
- 确实无法判断 → 清楚呈现双方内容,默认跳过,让用户决定。
- 只有
- 询问导入 / 导出 / 跳过。
- 执行操作——仅限本地文件:
- 导出(
Different/Only in DB):写入环境中的文件,并规范化尾随换行符(由拆分管理的项目写入拆分目录)。Only in sync+ 导出表示环境中没有该配置 → 确认后,使用git rm删除本地文件。 - 导入:保留本地文件;不做更改。⚠️
Only in DB+ 导入具有破坏性——环境中的配置不在 git 中,因此部署时执行完整的drush cim会从环境中删除该配置。明确警告,并要求再次确认。 - 跳过:不做任何操作。
- 导出(
6. 使用导入转换器验证——不要使用 config:status
写入导出的文件后,不要重新运行 config:status 来确认——即使文件已存在且有效,它仍可能将刚写入的项目报告为 Only in DB(这是显示信息过期导致的假象)。请使用 cim 实际采用的存储层——导入转换器来验证(它会像部署时一样应用 config_split):
drush ev '
$t = \Drupal::service("config.import_transformer")->transform(\Drupal::service("config.storage.sync"));
foreach (["<name1>","<name2>"] as $n) {
print "$n => " . ($t->exists($n) && in_array($n, $t->listAll(), true) ? "RECONCILED (deploy-safe)" : "MISSING — would be deleted on cim") . "\n";
}'
exists() && in listAll() = YES 表示实际部署会保留该配置。请以此为准,而不是 config:status 表,来判断“我的导出是否生效”。
7. 总结并交接
- 已导出(环境 → git): 创建、覆盖或移除的文件。
- 部署时保留(导入): 下次部署时,本地版本会应用到环境中的项目。
- 已跳过: 尚未解决的差异及其原因。
然后展示 git status 和 git diff --stat config/,不要自动提交或推送——先征求同意。请记住,Import 项目只有在代码部署完成且环境上运行配置导入后才会生效(完整的部署后续步骤及其验证见 drupal-deploy-safety 技能)。
注意事项
- 在参考环境上运行
config:status,比较的是该环境的同步目录和数据库——它看不到你尚未提交的本地编辑。请先提交并部署编辑内容,再协调剩余差异。 - 配置拆分:
prod/local拆分项目位于config/prod/config/local,而不是config/default。请始终将导出结果写回文件的实际位置。 - 仅涉及
_core的差异无害——不要因此反复修改文件。uuid差异则不同:导入会删除并重新创建配置实体,因此请导出环境中的值。