元の YAML
変更後の YAML

YAML diff: 2つのYAMLファイルをオンラインで比較

2つのYAMLドキュメントを貼り付けて、正確な左右比較を取得。Kubernetesマニフェスト、GitHub Actionsワークフロー、Helm values、docker-composeファイルに対応。

YAML diffツールとは?

2つのYAMLドキュメントを比較するための無料のブラウザ内ツールです。古いバージョンを左に、新しいバージョンを右に貼り付けると、違いが文字単位でハイライトされます。テキストはブラウザの外に出ません。シークレット参照や内部ホスト名を含むマニフェストをdiffする際にこれは重要です。

diffは文字レベルで動作し、テキストdiffツールと同じエンジンを使っています。エディタのYAMLモードはYAML 1.2.2 specificationに従ってシンタックスハイライトを処理するので、block scalars、anchors、flow collectionsはすべて正しく色付けされます。

Helmのvalues.yamlのpull requestで400行のdiffを見つめ、chartを壊した1つのインデントずれを探した経験があるなら、このツールがそれを数秒で見つけます。Slackとエディタの間でコピペしてスペースがタブに変換された場合にも便利です。YAMLはタブを受け付けません。

YAML diffの実際の仕組み

diffは文字レベルで動作し、その後セマンティッククリーンアップのパスがハイライトを意味のある塊にまとめます。バラバラの単独文字ではなくなります。挿入は右ペインに緑、削除は左ペインに赤で表示され、各ヘッダーの行カウントは検出された個別の編集数を示します。

YAMLには寛容な形式と勘違いした人を噛む解析ルールがあります。インデントはYAML 1.2.2 specに従い構造的なので、空白1つの位置ずれがドキュメントツリーを変えます。タブはインデントとして禁止されており、パーサーはそれをきっぱり拒否します。implicit typingはYAML 1.1で引用符のないトークンNOを真偽値falseに変換します。これが有名なNorway problemです: 国コードリストからノルウェーが密かに消えます。YAML 1.2はルールを絞り、truefalsenullと数値形式のみが引用符なしで変換されるようにしましたが、まだ多くのツールが1.1で解析しています。

下流のコンシューマー向けにYAMLをすでにJSONに変換しているなら、JSON diffツールがキー順序や正規化のような構造的な問題を扱います。JSONはYAML 1.2の厳密な部分集合なので、有効なJSONドキュメントはすべて有効なYAMLでもあります。この互換性はspecに記載されており、js-yamllibyamlの両方が驚きなくJSONをround-tripできる理由です。

3ステップでYAMLを比較する方法

テキストパネル2つ、diff 1つ。登録なし、アップロードなし、サーバーへの往復なし。

  1. 1

    YAMLを貼り付けるかアップロード

    古いYAMLを左、新しいYAMLを右に貼り付けます。あるいはどちらか一方のアップロードをクリックして、.yamlまたは.ymlファイルを直接読み込みます。サンプルボタンを押すと、両方のペインに小さなKubernetes Deploymentが入り、ツールの動作を先に確認できます。

  2. 2

    インデントが意図通りか確認

    YAMLはインデントにスペースのみを使い、タブは使いません。スペースをタブに変換するチャットクライアントやターミナルから貼り付けた場合、パーサーはファイルを拒否します。エディタはタブと行末の空白をハイライトするので、デプロイ失敗の原因になる前に発見できます。

  3. 3

    diffを読む

    削除は左に赤、挿入は右に緑で表示されます。両方のペインは同期してスクロールするので、長いマニフェストでも場所を見失わずに追えます。各ヘッダーの変更数は、diffが見つけた個別の編集数を要約しています。

YAML diffが正しいツールになるとき

staging とprodでKubernetes Deploymentのspecを比較

両方のクラスターでkubectl get deployment web -o yamlを実行し、出力をdiffします。スプリント終わりのロールアウトが届かなかったため、prodがまだreplicas: 2と古いイメージタグのままになっていることがよくあります。再度kubectl applyを実行する前に確認する最速の方法はテキストdiffです。KubernetesのオブジェクトモデルはYAMLそのものなので、これは日常的なケースです。

GitHub ActionsワークフローYAMLのdiff

ブランチ名変更後にワークフローがトリガーされなくなったり、ジョブが急に8分長くなったりしたら、.github/workflows/ci.ymlを直前のグリーンコミットとdiffします。原因はたいていon:フィルタの変更、actions/setup-nodecache:キーの削除、あるいはmatrixのエントリがnode-version: "18"(string)からnode-version: 18(number)に静かに変わって型チェッカーを引っかけたかのいずれかです。

デプロイ前のdocker-compose env変更レビュー

docker-compose.ymlmainのバージョンとdiffし、environment:のどのエントリを実際に変更したか確認します。新しい環境変数のリストを貼り付けて、その1つが別のサービスですでに設定されていたことを忘れる人がいます。すると上書きが他の場所のフラグを静かに切り替えます。diffはそれを明白にします。

リリース間でのHelm chart values.yamlの追跡

chartを1.8.0から2.0.0に上げる際、values.yamlをmaintainerが公開した新しいデフォルトとdiffします。Helmは値をキー単位でマージするので、トップレベルキーの名前変更(image.tagimage.repositoryの下に移動)は静かにchartのデフォルトにフォールバックします。helm upgradeがregressionをロールアウトする前に、diffがリネームを浮き上がらせます。

OpenAPIとSwagger YAMLスキーマレビュー

コードジェネレーターがpathsをアルファベット順に並べ替えると、3,000行のopenapi.yamlのdiffは読めません。バージョンを左右に並べると、実際の変更が浮かび上がります: requestスキーマに追加されたrequiredフィールドや、型がstringからintegerに静かに変わったresponseです。生成されたSDKを掘ってビルドが壊れた理由を探すより簡単です。

環境間のAnsibleプレイブックdiff

プレイブックがdevで動作しprodで失敗するとき、両者間でinventoryまたはroleのdefaults/main.ymlをdiffします。よくある原因は、コピーされなかったhostvar、あるいはdevではroleに、prodでは1つのtaskに設定されたbecome: yesです。diffがそれを数秒で見つけます。

YAMLクイックリファレンス

このツールが最もよく表面化させる解析のエッジケースについての短いカンニングペーパー。すべてYAML仕様と実際のパーサーの動作に基づいています。

TopicWhat this tool does
インデントスペースのみで、その数は構造的です。2スペースと4スペースは両方とも一般的です。ファイル単位でどちらか1つに決めて貫いてください。歴史を知りたい場合はWikipediaの YAML 概要に良いまとめがあります。
タブspecによりインデントとして禁止。スカラー値の中では許可されています。エディタがEnter時にタブを挿入する場合、.yaml.ymlファイルではスペースを使うように設定してください。
anchorsとaliases&nameがanchorを定義し、*nameがそれを参照します。コピペなしでcontainerのenv varsやデフォルトのservice configなど大きなブロックを繰り返すのに便利です。
merge keys<<: *baseは参照されたmappingを現在のmappingにマージします。YAML 1.1の機能です。libyamlを含むほとんどのパーサーはまだ受け入れます。YAML 1.2 specは廃止しました。
マルチドキュメントファイルハイフン3つ(---)が単一ストリーム内のドキュメントを区切ります。複数のKubernetesオブジェクトを1つのkubectl apply -fに通すのに便利です。...はドキュメントを終了します。
block scalars|は改行を保持(literal)、>は改行をスペースに折りたたみます。修飾子-+は末尾の改行を制御します。シェルスクリプトには|、長い人間向けの文章には>を使ってください。
Norway problem引用符のないNOYESONOFFはYAML 1.1で真偽値になります。引用符でくくるか、1.2のパーサーを使ってください。どの文字列が変換されるかはYAMLの型定義を参照してください。
エンコーディングYAML 1.2 specはUTF-8を要求します。UTF-16はBOM付きで許可されています。実際のツールはBOMなしのUTF-8を期待するので、驚きを避けるためにそのように保存してください。

YAML diff: よくある質問

YAMLの空白への敏感さはdiffにとって有利ですか不利ですか?

YAMLは空白に敏感なので、普通のテキストdiffでもすでに有用です: インデントの変更はすべて構造的な変更で、diffがそれを捕まえます。違いは見せ方にあります。YAMLモードはanchors、tags、block scalars、flow collectionsをシンタックスの色でハイライトするので、変更がキー、文字列値、リスト要素のどれに対するものかが一目でわかります。背後のdiffアルゴリズムはテキストdiffツールと同じです。

なぜYAMLはインデントとスペースにそんなに厳しいのですか?

インデントだけが、どのキーがどのmappingに属すかをパーサーに伝えるからです。YAML 1.2.2 specはノードのインデントレベルを先頭スペースの数で定義し、タブをインデントとして禁止しています。スペース1つ追加するだけで、キーがサブmappingに昇格します。その厳格さは、波括弧やカンマを必要としない形式の代償であり、JSONよりYAMLでインデントバグをよく見る理由です。

Norway problemとは何ですか?

YAML 1.1のimplicit typingは、引用符のないトークンNOを真偽値falseに変換します。なので、ノルウェーを表すNOを含む国コードのリストは、静かに1つのエントリがfalseに置き換わったリストになります。YESONOFFなどにも同じことが当てはまります。StrictYAMLが詳細に文書化しています。修正は値を引用符でくくる("NO")か、YAML 1.2に従うパーサーを使うことです。1.2はtruefalsenullのみを暗黙的に変換します。

anchors、aliases、merge keysはどう動きますか?

anchor (&name)はノードに印を付け、後でalias (*name)で参照できるようにし、長いファイルでの重複を避けます。merge key (<<: *name)はYAML 1.1の拡張で、参照されたmappingのすべてのキーを現在のmappingにコピーするもので、サービス間で共通設定を共有するのに便利です。merge keysはYAML 1.2の一部ではありませんが、js-yamlを含むほとんどのパーサーは互換性のためにまだサポートしています。diffはanchorsとaliasesをプレーンテキストとして扱うので、リネームされたanchorはきれいに見えます。

YAML diffツールにJSONを貼り付けられますか?

はい。JSONはYAML 1.2の厳密な部分集合なので、有効なJSONドキュメントは有効なYAMLドキュメントでもあります。本当に望むなら2つを混ぜることもでき、ブロックスタイルのファイルにJSONスタイルのflow collectionを落とすこともできます。純粋なJSON作業には、JSON diffツールにJSON対応のformatとvalidateボタンがあり、pretty-printとsort-keysも含まれます。

タブを使ったときにパーサーがファイルを拒否するのはなぜですか?

YAML specがインデントとしてのタブを禁止しているからです。1.2.2 specからの引用: "To maintain portability, tab characters must not be used in indentation"。タブはスカラー値の中では許可されています(文字列にタブを含められます)、ただインデントが測定される行頭ではダメです。修正方法は、ファイルがすでに使っている慣例に従って、タブから2スペースまたは4スペースに素早く検索置換することです。

プライバシーと仕組み

あなたのYAMLはブラウザの外に出ません。エディタ、シンタックスハイライター、diffはすべてあなたのマシン上、ローカルで動作します。入力に対する分析もログもクラウドへの往復もありません。私たちが従う形式はYAML 1.2.2 specificationです。何もアップロードされていないことを確認するには、比較中にDevToolsを開いてNetworkタブを見てください。