Zwei YAML-Dateien vergleichen, ohne an der Einrückung zu scheitern

Der schnellste Weg, zwei YAML-Dateien zu vergleichen, besteht darin, beide in ein nebeneinander angeordnetes Diff-Tool einzufügen, die Einrückung zu normalisieren und die hervorgehobenen Zeilen zu lesen. Das Vergleichen ist der einfache Teil. Bei YAML ist das Rauschen tückischer als üblich: ein versehentlicher Tab, ein umgeordneter Schlüssel oder ein von jemandem in Anführungszeichen gesetzter Wert können dazu führen, dass zwei Dateien, die zu denselben Daten laden, aussehen, als hätten sie nichts gemeinsam.

Dieser Leitfaden zeigt, wie man einen sauberen, zuverlässigen YAML-Diff erhält. Wir schauen uns an, warum zwei gleichwertige Dateien auf dem Papier auseinanderdriften, welche Methoden es wert sind, gekannt zu werden, und ein ausgearbeitetes Beispiel, dem man folgen kann. Wer einfach nur das Tool möchte, kann auf unserer YAML-Vergleichsseite all das im Browser erledigen.

Warum YAML-Dateien trügerisch schwer zu vergleichen sind

YAML ist ein leerzeichensensitives Format (siehe die YAML-1.2.2-Spezifikation), und genau das macht Diffs knifflig. Einrückung trägt Bedeutung, aber die Menge der Einrückung nicht, solange sie konsistent ist. So können eine mit zwei Leerzeichen eingerückte Datei und eine andere mit vier zur identischen Struktur laden, während jede Zeile für einen Textdiff anders aussieht.

Hier ist die zentrale Tatsache, die man behalten sollte: Ein YAML-Mapping ist eine Menge von Schlüssel/Wert-Paaren, und wie bei JSON-Objekten ändert die Reihenfolge dieser Schlüssel die Daten nicht. Also dies:

name: Ada Lovelace
role: editor

und dies:

role: editor
name: Ada Lovelace

laden zum selben Mapping, auch wenn ein Zeilendiff sie rot und grün malt. Die Elemente einer Sequenz hingegen sind geordnet, also ist das Umordnen einer Liste eine echte Änderung.

Sieht wie eine Änderung aus, ist es meist nicht
Was man im Diff siehtIst es eine echte Änderung?Was zu tun ist
2-Leerzeichen- vs. 4-Leerzeichen-EinrückungNein, nur die Konsistenz zähltBeide auf die gleiche Breite umformatieren
Mapping-Schlüssel in anderer ReihenfolgeNein, Mappings sind ungeordnetSchlüssel auf beiden Seiten sortieren
true vs. "true"Ja, boolean vs. StringUntersuchen, das ist real
name: Ada vs. name: "Ada"Nein, gleicher String-WertAnführungszeichen normalisieren
Flow-Stil [a, b] vs. Block-ListeNein, gleiche SequenzEinen Stil für beide wählen
Sequenz-Elemente in anderer ReihenfolgeJa, Sequenzen sind geordnetUntersuchen, das ist real

Zwei Zeilen dort sind echte Fallen. true ohne Anführungszeichen ist ein boolean; mit Anführungszeichen ist es der String "true", und diese Unterscheidung hat echte Ausfälle verursacht. Aber name: Ada und name: "Ada" sind derselbe String. Wer die technischen Details dazu nachlesen möchte, wie ein Parser das auflöst, findet im Abschnitt der Spezifikation über das core schema die Referenz.

Vier Methoden zum Vergleichen von YAML und wann man zu welcher greift

Es gibt keine einzige beste Methode. Es hängt davon ab, wo die Dateien liegen und was man herausfinden möchte. So schneiden die gängigen Optionen ab.

MethodeAm besten fürAufwandVersteht YAML?
Manuell durchlesenWinzige Dateien, ein oder zwei SchlüsselGeringNein, man ist der Parser
Online-Diff-ToolSchnelle Prüfungen, Einfügen von überallGeringMit Umformatierung ja
Befehlszeile (yq)Dateien auf der Festplatte, Scripting, Schlüssel sortierenMittelJa, wenn man zuerst sortiert
IDE oder git diffDateien bereits in einem RepositoryGering bei CommitsStandardmäßig zeilenbasiert

Für die meisten Menschen gewinnt ein Browser-Tool an Geschwindigkeit: nichts zu installieren, und man kann einen Ausschnitt direkt aus einem Kubernetes-Manifest oder einer CI-Konfiguration einfügen. Der Haken ist Formatierungsrauschen, das wir als Nächstes behandeln. Wer viel im Terminal arbeitet, sollte yq kennenlernen, das Schlüssel auf dieselbe Weise sortieren kann, wie es jq für JSON tut.

Der schnellste saubere Vergleich, Schritt für Schritt

Das ist die Vorgehensweise, die ich verwende, wenn mir jemand zwei Manifeste gibt und fragt: "Was ist anders?" Es dauert etwa fünfzehn Sekunden.

  1. Das YAML-Vergleichstool öffnen.
  2. Das Original links einfügen, die neue Version rechts.
  3. Auf beiden Seiten auf Formatieren klicken, damit sie die gleiche Einrückung verwenden.
  4. Schlüssel sortieren aktivieren, damit umgeordnete Mapping-Schlüssel nicht mehr als Änderungen erscheinen.
  5. Das Ergebnis lesen. Grün bedeutet hinzugefügt, rot bedeutet entfernt, und ein geänderter Wert erscheint als eines von beidem.

Schritt drei und vier sind der eigentliche Trick. Sobald beide Dateien die gleiche Einrückung verwenden und ihre Schlüssel sortiert sind, bleibt nur noch hervorgehoben, was sich tatsächlich geändert hat. Unser Diff-Engine basiert auf Googles diff-match-patch, das zuerst zeilenweise vergleicht und so auch bei langen Dateien schnell bleibt.

Ein ausgearbeitetes Beispiel

Angenommen, man prüft eine Änderung an einem Benutzerdatensatz. Hier ist der Vorher-Stand:

name: Ada Lovelace
role: editor
active: true
seats: 3

Und hier ist der Nachher-Stand, wie ein Teammitglied ihn übergeben hat:

active: true
name: Ada Lovelace
role: admin
seats: 5
team: platform

Wirft man diese in einen einfachen Zeilendiff, sieht es aus, als hätte sich fast jede Zeile verschoben, weil die Schlüssel in anderer Reihenfolge sind. Formatiert und sortiert man beide, ist die eigentliche Geschichte kurz:

Was sich tatsächlich geändert hat
SchlüsselVorherNachherÄnderung
roleeditoradminGeändert
seats35Geändert
teamplatformHinzugefügt
nameAda LovelaceAda LovelaceKeine Änderung
activetruetrueKeine Änderung (nur verschoben)

Drei echte Bearbeitungen: eine Rollenerhöhung, eine Sitzanzahl und ein neuer Team-Schlüssel. Die Umsortierung war Rauschen. Diese Beförderung von editor zu admin ist genau die Art von Sache, die man im Review erkennen möchte, und sie ist leicht zu übersehen, wenn sie unter falschen Positivmeldungen vergraben ist.

Formatierungsrauschen in der Befehlszeile beseitigen

Wenn die Dateien bereits auf der Festplatte liegen, funktioniert die gleiche "Umformatieren und Sortieren"-Idee mit zwei kurzen Befehlen. yq kann Schlüssel sortieren und eine kanonische Form neu ausgeben, sodass ein einfacher Diff danach ehrlich ist:

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

Jetzt meldet diff nur noch Werte, die sich wirklich geändert haben, weil beide Dateien die gleiche Einrückung und die gleiche Schlüsselreihenfolge haben. Das ist das Terminal-Äquivalent zu Formatieren und Schlüssel sortieren im Browser.

Die Fallstricke, die nur YAML kennt

Einige YAML-Funktionen verursachen Diffs, die Leute überraschen. Anchors und aliases (&name und *name) lassen eine Datei einen Wert per Referenz wiederholen, während eine andere ihn vollständig ausschreibt; beide laden zu denselben Daten, lesen sich aber völlig unterschiedlich. Das berüchtigte "Norwegen-Problem" ist ein weiteres: no, off und yes ohne Anführungszeichen können in älteren YAML-1.1-Parsern als booleans interpretiert werden, sodass country: NO zu false werden könnte. YAML 1.2 hat das Schema korrigiert, aber viele Tools bringen weiterhin das 1.1-Verhalten mit. Wenn ein Wert aussieht, als hätte er den Typ gewechselt, ist das das Erste, was man prüfen sollte.

Häufige Stolperfallen, auf die man achten sollte

StolperfalleWarum sie zuschlägtLösung
Tabs für die EinrückungYAML verbietet Tabs für die Einrückung; die Datei lässt sich womöglich nicht einmal parsenTabs zuerst in Leerzeichen umwandeln
Skalare mit oder ohne Anführungszeichen"true" ist ein String, true ist ein booleanDas kann eine echte Änderung sein, nicht abtun
Anchors und aliasesEine Datei setzt den Wert inline, die andere referenziert ihnAnchors auflösen, dann die expandierte Form vergleichen
Das Norwegen-Problemno kann in YAML 1.1 als false geparst werdenMehrdeutige Strings in Anführungszeichen setzen; Parser-Version prüfen
Nachgestellte LeerzeichenUnsichtbare Leerzeichen nach einem Wert erscheinen als ÄnderungNachgestellte Leerzeichen vor dem Vergleich entfernen

YAML und JSON sind enger verwandt, als sie aussehen

Jedes JSON-Dokument ist gültiges YAML, weil YAML 1.2 eine Obermenge von JSON ist. Das ist praktisch zum Vergleichen: Wenn die Einrückung oder die anchors einem zu schaffen machen, konvertiert man beide Dateien zu JSON, formatiert sie gleich und vergleicht das stattdessen. Viele Parser, darunter PyYAML, machen einen Round-Trip von YAML zu einer einfachen Datenstruktur, die man als JSON neu ausgeben kann, was die stilistischen Unterschiede entfernt und nur die Daten übrig lässt.

Verwandte Tools

YAML reist selten allein. Wenn man die JSON-Form derselben Daten vergleicht, wendet JSON-Vergleich dieselbe Idee an. Umgebungseinstellungen und .env-Dateien passen gut auf die Konfigurations-Vergleichsseite, und Änderungen zwischen zwei API-Aufrufen zu überprüfen ist genau das, wofür das API-Antwort-Diff gebaut wurde.

Häufig gestellte Fragen

Werden YAML-Dateien beim Online-Vergleich irgendwo hochgeladen?
Auf comparetext.org läuft der Diff im Browser. Die beiden YAML-Dateien werden von JavaScript auf dem eigenen Computer verglichen, sodass nichts an einen Server gesendet wird, es sei denn, man klickt ausdrücklich auf Speichern oder Teilen. Das macht es sicher für Kubernetes-Manifeste, CI-Konfigurationen und andere Daten, die man nicht auf einer Website einfügen möchte, die bei jedem Tastendruck hochlädt.
Warum zeigen meine zwei YAML-Dateien jede Zeile als unterschiedlich an?
Fast immer ist es Formatierung, keine echten Änderungen. Eine Datei ist mit zwei Leerzeichen eingerückt, die andere mit vier, oder die Mapping-Schlüssel sind in anderer Reihenfolge, oder eine verwendet Anführungszeichen und die andere nicht. Beide Seiten auf die gleiche Einrückung umformatieren und die Schlüssel sortieren, damit die Reihenfolge keine Rolle mehr spielt. Danach schrumpft der Diff meist auf die wenigen Werte, die sich wirklich geändert haben.
Spielt die Einrückungsbreite beim Vergleichen von YAML eine Rolle?
Nicht für die Bedeutung, nur für die Konsistenz. YAML nutzt die Einrückung, um die Struktur zu zeigen, aber es ist egal, ob man zwei oder vier Leerzeichen verwendet, solange jede Ebene innerhalb der Datei konsistent ist. So können eine Zwei-Leerzeichen-Datei und eine Vier-Leerzeichen-Datei identische Daten enthalten und für einen Textdiff trotzdem völlig verschieden aussehen. Beide auf die gleiche Breite umzuformatieren entfernt diesen falschen Unterschied. Tabs sind für die Einrückung jedoch überhaupt nicht erlaubt.
Wie vergleiche ich YAML und ignoriere dabei die Schlüsselreihenfolge?
YAML-Mapping-Schlüssel sind ungeordnet, also enthalten zwei Dateien mit denselben Schlüsseln in anderer Reihenfolge dieselben Daten. Damit ein Textdiff zustimmt, sortiere man die Schlüssel vor dem Vergleich auf beiden Seiten. Im Browser die Option Schlüssel sortieren (kanonisieren) verwenden. In der Befehlszeile erledigt das yq mit sort_keys. Sobald beide Dateien Schlüssel in derselben sortierten Reihenfolge haben, erscheinen nur noch echte Wertänderungen. Sequenz-Elemente bleiben geordnet, also nicht sortieren.
Was ist das Norwegen-Problem in YAML?
Es ist ein klassischer YAML-Stolperstein, bei dem der Wert NO ohne Anführungszeichen als boolean false statt als String "NO" geparst wird, sodass ein Ländercode für Norwegen zu false wird. Es passiert in YAML-1.1-Parsern, die yes, no, on und off als booleans behandeln. YAML 1.2 hat die Regeln verengt, aber viele Tools bringen weiterhin das 1.1-Verhalten mit. Wenn ein Wert in deinem Diff von einem Wort zu true oder false gewechselt zu sein scheint, ist ein boolean-ähnlicher String ohne Anführungszeichen die wahrscheinliche Ursache. Den Wert in Anführungszeichen zu setzen behebt es.
Kann ich große YAML-Dateien vergleichen, ohne dass die Seite einfriert?
Ja, bis zu einem gewissen Punkt. Ein zeilenbasierter Diff bleibt bei Dateien mit Tausenden von Zeilen schnell, weil er zunächst ganze Zeilen statt jedes einzelnen Zeichens vergleicht. Sehr große Dateien (mehrere Megabyte) lassen sich besser mit einem Befehlszeilentool wie yq oder git diff bearbeiten, das die Daten streamt. Für alles, was man bequem in einem Browser durchscrollen kann, ist ein Online-Diff die schnellere Option.

Bereit, es auszuprobieren? Dateien in das YAML-Vergleichstool einfügen und sehen, was sich geändert hat.