インデントに悩まされずに2つのYAMLファイルを比較する方法
2つのYAMLファイルを比較する最速の方法は、両方をサイドバイサイドのdiffツールに貼り付け、 インデントを正規化して、ハイライトされた行を読むことです。比較そのものは簡単な部分です。 YAMLではノイズが通常より厄介で、紛れ込んだタブ、並び替えられたキー、誰かが引用符で囲んだ値によって、 同じデータを読み込む2つのファイルがまるで共通点がないように見えてしまいます。
このガイドでは、クリーンで信頼できるYAMLのdiffを取得する方法を解説します。 等価な2つのファイルが紙の上で乖離する理由、知っておく価値のある手法、 そして実際に試せる実例を紹介します。ツールだけが必要な場合は、 YAML比較ページでブラウザ上のすべてを処理できます。
YAMLファイルの比較が意外と難しい理由
YAMLは空白に敏感な形式であり(YAML 1.2.2仕様を参照)、 それがまさにdiffを厄介にする原因です。インデントには意味がありますが、 インデントの量には意味がありません。一貫していれば問題ないのです。 そのため、2スペースでインデントされたファイルと4スペースのファイルが同一の構造を読み込んでいても、 テキストdiffにはすべての行が違って見えます。
覚えておくべき重要な事実があります。YAMLのマッピングはキー/値のペアの集合であり、 JSONオブジェクトと同様、それらのキーの順序はデータを変えません。つまり、これ:
name: Ada Lovelace
role: editor
と、これ:
role: editor
name: Ada Lovelace
は同じマッピングを読み込みますが、行ベースのdiffでは赤と緑に塗られます。 一方、シーケンスの要素は順序付きなので、リストを並び替えることは本物の変更です。
| diffで見えるもの | 本当の変更か? | 対処法 |
|---|---|---|
| 2スペースvs 4スペースのインデント | いいえ、一貫性だけが重要 | 両方を同じ幅に再フォーマットする |
| マッピングのキーが異なる順序 | いいえ、マッピングは順序なし | 両側のキーをソートする |
true vs "true" | はい、boolean vs 文字列 | 調査が必要、これは本物 |
name: Ada vs name: "Ada" | いいえ、同じ文字列値 | 引用符を正規化する |
フロースタイル [a, b] vs ブロックリスト | いいえ、同じシーケンス | 両方に1つのスタイルを選ぶ |
| シーケンスの要素が異なる順序 | はい、シーケンスは順序付き | 調査が必要、これは本物 |
この2行は本物の落とし穴です。引用符のないtrueはbooleanですが、
引用符付きでは文字列"true"であり、その区別は実際の障害を引き起こしてきました。
しかしname: Adaとname: "Ada"は同じ文字列です。
パーサーがこれをどう解決するかの詳細は、仕様の
core schema
に関するセクションが参考になります。
YAMLを比較する4つの方法とその使い分け
唯一の最良の方法はありません。ファイルがどこにあるか、何を調べたいかによって異なります。 よく使われる方法を比較します。
| 方法 | 向いている場面 | 手間 | YAMLを理解するか? |
|---|---|---|---|
| 目視確認 | 小さなファイル、1〜2キー | 低 | いいえ、あなたがパーサー |
| オンラインdiffツール | クイックチェック、どこからでも貼り付け可能 | 低 | 再フォーマットすれば対応 |
コマンドライン(yq) | ディスク上のファイル、スクリプティング、キーのソート | 中 | 最初にソートすれば対応 |
IDEまたはgit diff | リポジトリ内のファイル | コミット済みなら低 | デフォルトは行ベース |
ほとんどの人にとって、ブラウザツールはインストール不要で、Kubernetesマニフェストや CI設定からスニペットを直接貼り付けられるため、速度面で優れています。問題はフォーマットのノイズで、 次で対処します。ターミナルで作業する場合は、yq が学ぶべきツールで、jqがJSONに対して行うのと同じようにキーをソートできます。
最速のクリーン比較、ステップバイステップ
誰かが2つのマニフェストを渡して「何が違うの?」と聞いてきたときに使うルーティンです。 約15秒で完了します。
- YAML比較ツールを開く。
- 左に元のファイル、右に新しいバージョンを貼り付ける。
- 両側でフォーマットをクリックして、同じインデントを共有するようにする。
- キーのソートをオンにして、並び替えられたマッピングのキーが変更として表示されないようにする。
- 結果を読む。緑が追加、赤が削除、変更された値はそれぞれ1つずつ表示される。
ステップ3と4がポイントです。両方のファイルが同じインデントを使用し、 キーがソートされると、ハイライトされるのは実際に変更された内容だけになります。 diffエンジンはGoogleの diff-match-patch を基盤としており、最初に行単位で比較するため、長いファイルでも高速に動作します。
実例
あるユーザーレコードへの変更をレビューしているとします。変更前:
name: Ada Lovelace
role: editor
active: true
seats: 3
そして、チームメイトから受け取った変更後:
active: true
name: Ada Lovelace
role: admin
seats: 5
team: platform
これをプレーンな行ベースdiffに入力すると、キーの順序が違うためほぼすべての行が移動したように見えます。 両方を再フォーマットしてソートすると、実際の話は短くなります:
| キー | 変更前 | 変更後 | 変更 |
|---|---|---|---|
role | editor | admin | 変更 |
seats | 3 | 5 | 変更 |
team | — | platform | 追加 |
name | Ada Lovelace | Ada Lovelace | 変更なし |
active | true | true | 変更なし(移動のみ) |
本物の変更は3つ:ロールの昇格、シート数、新しいチームキー。
並び替えはノイズでした。editorからadminへの昇格は
レビューで捉えたい変更ですが、誤検知に埋もれていると見逃しやすいです。
コマンドラインでフォーマットのノイズを除去する
ファイルがすでにディスクにある場合、同じ「再フォーマットとソート」のアイデアを
2つの短いコマンドで実現できます。yqはキーをソートして正規形を再出力できるので、
その後のプレーンdiffが正確になります:
yq -P 'sort_keys(..)' old.yaml > old.sorted.yaml
yq -P 'sort_keys(..)' new.yaml > new.sorted.yaml
diff old.sorted.yaml new.sorted.yaml
これでdiffは本当に変更された値のみを報告します。両ファイルが同じインデントと
同じキー順序を持つためです。これはブラウザでフォーマットとキーのソートをクリックする
ターミナル版です。
YAML特有の落とし穴
いくつかのYAMLの機能は人を驚かせるdiffを引き起こします。anchorsとaliases
(&nameと*name)により、一方のファイルが参照で値を繰り返し、
もう一方がそれを完全に書き出すことができます。両方とも同じデータを読み込みますが、
まったく違って読めます。悪名高い「ノルウェー問題」も別の例です。引用符のない
no、off、yesは古いYAML 1.1パーサーでbooleanとして
パースされる可能性があり、country: NOがfalseになることがあります。
YAML 1.2はスキーマを修正しましたが、多くのツールが今も1.1の動作を出荷しています。
値が型を変えたように見えたら、まずそれを確認します。
注意すべき一般的な落とし穴
| 落とし穴 | なぜ問題になるか | 対処法 |
|---|---|---|
| インデントにタブ | YAMLはインデントにタブを禁止している。ファイルがパースさえできないことがある | まずタブをスペースに変換する |
| 引用符あり vs なしのスカラー | "true"は文字列、trueはboolean | これは本物の変更の可能性がある、無視しないこと |
| anchorsとaliases | 一方のファイルは値をインラインに、もう一方は参照する | anchorsを解決してから展開形を比較する |
| ノルウェー問題 | noはYAML 1.1でfalseとしてパースされることがある | 曖昧な文字列に引用符を付ける。パーサーのバージョンを確認する |
| 行末の空白 | 値の後の見えない空白が変更として表示される | 比較前に行末の空白をトリムする |
YAMLとJSONは見た目より近い
YAML 1.2はJSONのスーパーセットなので、すべてのJSONドキュメントは有効なYAMLです。 これは比較に便利です。インデントやanchorsに苦戦している場合は、両方のファイルをJSONに変換し、 同じ形式にフォーマットして、それをdiffすればよいのです。 PyYAML を含む多くのパーサーは、YAMLをプレーンなデータ構造にラウンドトリップでき、それをJSONとして再出力できます。 これによりスタイルの違いが取り除かれ、データだけが残ります。
関連ツール
YAMLだけを扱うことはほとんどありません。同じデータのJSON形式を比較するなら、
JSON比較が同じアイデアを適用します。
環境設定と.envファイルは
設定比較ページでうまく並びます。
2つのAPI呼び出し間の変更をレビューするのは
APIレスポンスdiffのためのものです。
よくある質問
- YAMLファイルをオンラインで比較するとどこかにアップロードされますか?
- comparetext.orgではdiffはブラウザで実行されます。2つのYAMLファイルはあなた自身のマシン上のJavaScriptによって比較されるため、明示的に保存または共有をクリックしない限り、サーバーには何も送信されません。Kubernetesマニフェスト、CI設定、キーストロークのたびにアップロードするサイトに貼り付けたくないデータにも安全です。
- 2つのYAMLファイルがすべての行で差異があると表示されるのはなぜですか?
- ほぼ常にフォーマットの問題であり、本物の変更ではありません。一方のファイルが2スペース、もう一方が4スペースでインデントされている、あるいはマッピングのキーの順序が異なる、または一方が引用符を使い他方が使わない、といったことです。両側を同じインデントに再フォーマットし、キーをソートして順序が問題にならないようにします。その後、diffは本当に変更された少数の値に縮小されます。
- YAMLを比較するときインデント幅は重要ですか?
- 意味の上では重要ではなく、一貫性のためだけです。YAMLは構造を示すためにインデントを使いますが、ファイル内で各レベルが一貫している限り、2スペースか4スペースかは気にしません。そのため、2スペースのファイルと4スペースのファイルが同一のデータを保持していても、テキストdiffにはまったく違って見えます。両方を同じ幅に再フォーマットすると、その偽の差異が取り除かれます。ただしタブはインデントにまったく許可されていません。
- キー順序を無視してYAMLを比較するにはどうすればよいですか?
- YAMLのマッピングのキーには順序がないため、同じキーを異なる順序で持つ2つのファイルは同じデータを保持します。テキストdiffを一致させるには、比較前に両側のキーをソートします。ブラウザではキーのソート(正規化)オプションを使用します。コマンドラインでは、yqがsort_keysで実行します。両ファイルのキーが同じソート順になると、本物の値の変更のみが表示されます。シーケンスの要素は順序を保つので、それらはソートしないでください。
- YAMLのノルウェー問題とは何ですか?
- 引用符のない値NOが文字列"NO"ではなくboolean falseとしてパースされる、YAMLの古典的な落とし穴です。そのためノルウェーの国コードがfalseになってしまいます。これはyes、no、on、offをbooleanとして扱うYAML 1.1パーサーで起こります。YAML 1.2はルールを狭めましたが、多くのツールが今も1.1の動作を出荷しています。diffで値が単語からtrueまたはfalseに変わったように見えたら、引用符のないboolean風の文字列が原因の可能性が高いです。値を引用符で囲めば直ります。
- ページがフリーズせずに大きなYAMLファイルを比較できますか?
- はい、ある程度まで。行モードdiffは、各文字ではなくまず行全体を比較するため、数千行のファイルでも高速です。非常に大きなファイル(数メガバイト)は、データをストリームするyqやgit diffなどのコマンドラインツールで処理する方が適しています。ブラウザで快適にスクロールできるものなら、オンラインdiffが速い選択肢です。
試してみませんか?YAML比較ツールにファイルを貼り付けて、何が変わったか確認しましょう。