drupal-config-reconcile について
drupal-config-reconcileは、管理対象のDrupal設定とデプロイ環境の差異を調整するワークフローです。差異を項目ごとに確認し、インポート、エクスポート、保留を選べるようにします。書き込み先はローカルファイルに限定されます。
主な機能
- 01管理対象設定と参照環境の比較
- 02差異をインポート・エクスポート・保留に分類
- 03config: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 Reconcile
追跡対象の設定(config/default と各種 split ディレクトリ)と、デプロイ済み環境のアクティブな設定とのずれを解消するためのガイド付きワークフローです。ほとんどのチームは仕組み(config:status、cim、cex)を把握していますが、差分を項目ごとに確認し、どちらを採用するかを決める規律ある方法がありません。このワークフローは、そのための規律を提供します。
核となる判断:インポート、エクスポート、スキップ
差分のある設定項目は、必ず次の3つのいずれかに該当するため、適用する方向を選びます。
- インポート = ディスク → DB。 追跡対象のファイルを信頼できる唯一の情報源とし、次回のコードデプロイと設定インポートで環境に反映します。ファイルは変更せず、git の内容を維持します。
- エクスポート = DB → ディスク。 環境の値を採用し、その設定を追跡対象のファイルに書き込みます(環境に設定が存在しない場合は、
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> |
| 本番環境から非本番環境へ DB を更新 | Cloud 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 の post-rollout タスク | drush sql:sync @<prod> @<env> |
| DB をローカルに取得 | 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 が提供する @platform.<env> | drush sa (Lagoon が提供) | drush/sites/ 内のエイリアス |
各プラットフォームで一度だけ認証・リンクします: Acquia は
acli auth:login+acli link、Pantheon はterminus auth:login、Platform.sh/Upsun はplatform login/upsun login、Lagoon はlagoon loginを実行します。いずれの環境でも、本番環境に対する書き込み・クローン操作は決して実行しないでください。
ワークフロー
1. 参照環境を選ぶ(live/prod は決して選ばない)
本番環境の代わりとして非本番環境を使用します(例:Pantheon の dev/test、または CI/ステージングのエイリアス)。ライブ環境を対象にすることは拒否してください。ライブ環境への設定書き込みは、本番環境の設定を破壊する原因になります。
2. 参照 DB を最新にする
差分に意味があるのは、参照環境が現在の本番環境を反映している場合に限られます。環境の DB が古い場合(通常は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. 差分を参照環境で取得する(ローカルではなく)
Drupal が設定スプリットと config_exclude_modules を正しく適用できるよう、参照環境で config:status を実行します。ローカルで実行すると、開発専用モジュール(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 は、一時的な出力先の下に相対パスのスプリットディレクトリを作成しようとして失敗することがよくあります。また、SSH コマンドの検出方法は Terminus のバージョンによって不安定です。必要な項目をその都度取得します。
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)はファイル末尾の改行が 2 つあると拒否し、プリコミットフックでコミットがブロックされます。ファイルを書き込む際は、末尾の改行を 1 つだけに正規化します。
printf '%s\n' "$(cat /tmp/ref-<name>.yml)" > config/default/<name>.yml
5. 各項目を 1 つずつ確認する
進捗がわかるように、設定名ごとに 1 項目ずつ TODO リストを作成します。次の順に処理します。Only in DB、Different、Only in sync。各項目について:
- ローカルファイルを探します。 通常は
config/default/<name>.ymlにあります。そこになければ、見つからないと判断する前にスプリットディレクトリ(config/prod/、config/local/、config/envs/…)を確認します。スプリットで管理される項目はconfig/defaultの外にあり、同じスプリットディレクトリに書き戻す必要があります。 - 内容の差分を表示します(左側はローカル/ディスク、右側は環境/DB):
Different:diff -u config/default/<name>.yml /tmp/ref-<name>.ymlOnly in DB:ローカルにない場合は、環境の内容全体を表示します。Only in sync:環境にない場合は、ローカルファイルの内容全体を表示します。
- 理由とともに、どちらの方向で処理するかを提案します:
Only in DB→ エクスポート。 環境内(UI または更新フック)で作成された設定で、Git に取り込むべきものです(メッセージテンプレート、ビューの表示設定など)。Only in sync→ インポート。 コードに追加されたものの、まだデプロイされていない新しい設定です。保持してデプロイできるようにします。Different:_coreだけが異なる → スキップ。 問題のない環境由来の差異です。ファイルを無駄に変更しないでください。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/ を表示し、自動でコミットやプッシュはしないでください。まず確認を求めてください。インポート項目が有効になるのは、コードがデプロイされ、環境で設定インポートが実行された後だけです(デプロイ後半の手順と検証については、drupal-deploy-safety スキルを参照してください)。
注意点
- 参照環境での
config:statusは、その環境の sync ディレクトリと DB を比較します。未コミットのローカル編集は確認できません。先に編集をコミットしてデプロイし、その後、残っている差分を調整してください。 - Config split:
prod/localの split 項目はconfig/defaultではなく、config/prod/config/localにあります。エクスポート結果は必ずファイルの実際の場所に書き戻してください。 _coreのみの差分は問題ありません。これを理由にファイルを変更しないでください。uuidの差分は問題になります。インポートすると設定エンティティが削除され、再作成されるため、環境側の値をエクスポートしてください。