Twee YAML-bestanden vergelijken zonder gedoe met inspringing

De snelste manier om twee YAML-bestanden te vergelijken is beide in een diff-tool naast elkaar te plakken, de inspringing te normaliseren en de gemarkeerde regels te lezen. Het vergelijken is het makkelijke deel. Bij YAML is de ruis verraderlijker dan gewoonlijk: een verdwaalde tab, een omgewisselde sleutel of een waarde die iemand tussen aanhalingstekens zette, kunnen twee bestanden die naar dezelfde data laden eruit laten zien alsof ze niets gemeen hebben.

Deze gids loopt door hoe je een schone, betrouwbare YAML-diff krijgt. We bekijken waarom twee gelijkwaardige bestanden op papier uit elkaar drijven, welke methoden het waard zijn om te kennen en een uitgewerkt voorbeeld dat je kunt volgen. Als je gewoon de tool wilt, doet onze YAML-vergelijkpagina dit allemaal in de browser.

Waarom YAML-bestanden bedrieglijk lastig te vergelijken zijn

YAML is een spatiegevoelig formaat (zie de YAML 1.2.2-specificatie), en juist dat maakt diffs lastig. Inspringing draagt betekenis, maar de hoeveelheid inspringing niet, zolang ze consistent is. Dus een bestand ingesprongen met twee spaties en een ander met vier kunnen naar de identieke structuur laden terwijl elke regel er voor een tekstdiff anders uitziet.

Hier is het kernfeit om vast te houden: een YAML-mapping is een set sleutel/waarde- paren en, net als JSON-objecten, verandert de volgorde van die sleutels de data niet. Dus dit:

name: Ada Lovelace
role: editor

en dit:

role: editor
name: Ada Lovelace

laden naar dezelfde mapping, ook al kleurt een regeldiff ze rood en groen. De items van een sequence zijn daarentegen geordend, dus het omwisselen van een lijst is een echte wijziging.

Lijkt een wijziging, maar is het meestal niet
Wat je in de diff zietIs het een echte wijziging?Wat te doen
2-spaties- vs 4-spaties-inspringingNee, alleen consistentie teltHerformatteer beide naar dezelfde breedte
Mapping-sleutels in andere volgordeNee, mappings zijn ongeordendSorteer de sleutels aan beide kanten
true vs "true"Ja, boolean vs stringOnderzoek dit, het is echt
name: Ada vs name: "Ada"Nee, dezelfde stringwaardeNormaliseer de aanhalingstekens
Flow-stijl [a, b] vs bloklijstNee, dezelfde sequenceKies één stijl voor beide
Sequence-items in andere volgordeJa, sequences zijn geordendOnderzoek dit, het is echt

Twee rijen daar zijn echte valkuilen. true zonder aanhalingstekens is een boolean; mét aanhalingstekens is het de string "true", en dat onderscheid heeft echte storingen veroorzaakt. Maar name: Ada en name: "Ada" zijn dezelfde string. Wil je het technische detail over hoe een parser dit oplost, dan is de sectie van de specificatie over het core schema de referentie.

Vier manieren om YAML te vergelijken en wanneer je welke pakt

Er is geen enkele beste methode. Het hangt af van waar de bestanden staan en wat je wilt achterhalen. Zo verhouden de gangbare opties zich.

MethodeHet best voorMoeiteBegrijpt YAML?
Op het oog nakijkenPiepkleine bestanden, één of twee sleutelsLaagNee, jij bent de parser
Online diff-toolSnelle controles, vanaf overal plakkenLaagMet herformatteren, ja
Opdrachtregel (yq)Bestanden op schijf, scripting, sleutels sorterenGemiddeldJa, als je eerst sorteert
IDE of git diffBestanden al in een repositoryLaag bij commitStandaard regelgebaseerd

Voor de meeste mensen wint een browsertool op snelheid: niets te installeren, en je kunt een fragment rechtstreeks uit een Kubernetes-manifest of een CI-config plakken. De adder onder het gras is formatteringsruis, die we hierna behandelen. Leef je in de terminal, dan is yq de tool om te leren, en die kan sleutels op dezelfde manier sorteren als jq dat voor JSON doet.

De snelste schone vergelijking, stap voor stap

Dit is de routine die ik gebruik wanneer iemand me twee manifests aanreikt en vraagt "wat is er anders?" Het kost ongeveer vijftien seconden.

  1. Open de YAML-vergelijktool.
  2. Plak het origineel links en de nieuwe versie rechts.
  3. Klik aan beide kanten op Formatteren zodat ze dezelfde inspringing delen.
  4. Zet sleutels sorteren aan zodat omgewisselde mapping-sleutels niet langer als wijzigingen verschijnen.
  5. Lees het resultaat. Groen is toegevoegd, rood is verwijderd, en een gewijzigde waarde verschijnt als één van elke kleur.

Stap drie en vier zijn de hele truc. Zodra beide bestanden dezelfde inspringing gebruiken en hun sleutels gesorteerd zijn, blijft alleen nog over wat er daadwerkelijk veranderde om uit te lichten. Onze diff-engine is gebouwd op Googles diff-match-patch, die eerst regel voor regel vergelijkt en zo snel blijft, zelfs bij lange bestanden.

Een uitgewerkt voorbeeld

Stel dat je een wijziging aan een gebruikersrecord nakijkt. Hier is het ervoor:

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

En hier is het erna, zoals een teamgenoot het aan je gaf:

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

Gooi die in een ruwe regeldiff en het lijkt of bijna elke regel is verschoven, omdat de sleutels in een andere volgorde staan. Herformatteer en sorteer beide, en het echte verhaal is kort:

Wat er werkelijk veranderde
SleutelErvoorErnaWijziging
roleeditoradminGewijzigd
seats35Gewijzigd
teamplatformToegevoegd
nameAda LovelaceAda LovelaceGeen wijziging
activetruetrueGeen wijziging (alleen verplaatst)

Drie echte bewerkingen: een rolverhoging, een aantal stoelen en een nieuwe team-sleutel. Het omwisselen was ruis. Die promotie van editor naar admin is precies het soort dat je in een review wilt opvangen, en het is makkelijk te missen wanneer het onder valse positieven begraven ligt.

De formatteringsruis op de opdrachtregel uitschakelen

Als je bestanden al op schijf staan, werkt hetzelfde "herformatteer en sorteer"-idee met twee korte commando's. yq kan sleutels sorteren en een canonieke vorm opnieuw uitvoeren, zodat een gewone diff daarna eerlijk is:

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

Nu rapporteert diff alleen waarden die echt veranderden, omdat beide bestanden dezelfde inspringing en dezelfde sleutelvolgorde hebben. Dit is het terminalequivalent van klikken op Formatteren en sleutels sorteren in de browser.

De valkuilen die uniek zijn voor YAML

Een paar YAML-functies veroorzaken diffs die mensen verrassen. Anchors en aliases (&name en *name) laten het ene bestand een waarde per referentie herhalen terwijl een ander hem voluit uitschrijft; beide laden naar dezelfde data maar lezen compleet anders. Het beruchte "Noorwegen-probleem" is een ander: ongeciteerde no, off en yes kunnen als booleans worden geparseerd in oudere YAML 1.1-parsers, dus country: NO kan false worden. YAML 1.2 heeft het schema gerepareerd, maar veel tools leveren nog 1.1-gedrag. Wanneer een waarde lijkt te zijn veranderd van type, is dat het eerste om te controleren.

Veelvoorkomende valkuilen om op te letten

ValkuilWaarom het bijtOplossing
Tabs voor inspringingYAML verbiedt tabs voor inspringing; het bestand parseert misschien niet eensZet tabs eerst om naar spaties
Scalars met of zonder aanhalingstekens"true" is een string, true is een booleanDit kan een echte wijziging zijn, wuif het niet weg
Anchors en aliasesHet ene bestand zet de waarde inline, het andere refereert eraanLos de anchors op en vergelijk dan de uitgevouwen vorm
Het Noorwegen-probleemno kan in YAML 1.1 als false worden geparseerdZet dubbelzinnige strings tussen aanhalingstekens; controleer je parserversie
Witruimte aan regeleindeOnzichtbare spaties na een waarde verschijnen als wijzigingKnip de afsluitende witruimte weg voor het vergelijken

YAML en JSON liggen dichter bij elkaar dan ze lijken

Elk JSON-document is geldig YAML, want YAML 1.2 is een superset van JSON. Dat is handig voor vergelijken: als de inspringing of de anchors je dwarszitten, converteer beide bestanden naar JSON, formatteer ze op dezelfde manier en diff dat. Veel parsers, waaronder PyYAML, maken een round-trip van YAML naar een eenvoudige datastructuur die je als JSON opnieuw kunt uitvoeren, wat de stilistische verschillen wegneemt en alleen de data overlaat.

Gerelateerde tools

YAML reist zelden alleen. Vergelijk je de JSON-vorm van dezelfde data, dan past JSON vergelijken hetzelfde idee toe. Omgevingsinstellingen en .env-bestanden lijnen goed uit op de config-vergelijkpagina, en wijzigingen tussen twee API-aanroepen nakijken is waarvoor de API-respons-diff is gebouwd.

Veelgestelde vragen

Worden YAML-bestanden bij online vergelijken ergens geüpload?
Op comparetext.org draait de diff in je browser. De twee YAML-bestanden worden vergeleken door JavaScript op je eigen machine, dus er wordt niets naar een server gestuurd tenzij je expliciet op Opslaan of Delen klikt. Dat maakt het veilig voor Kubernetes-manifests, CI-configs en andere data die je niet zou willen plakken in een site die bij elke toetsaanslag uploadt.
Waarom tonen mijn twee YAML-bestanden elke regel als verschillend?
Bijna altijd is het opmaak, geen echte wijzigingen. Het ene bestand is met twee spaties ingesprongen, het andere met vier, of de mapping-sleutels staan in een andere volgorde, of de een gebruikt aanhalingstekens en de ander niet. Herformatteer beide kanten naar dezelfde inspringing en sorteer de sleutels zodat de volgorde niet meer uitmaakt. Daarna krimpt de diff meestal tot het handjevol waarden dat echt veranderde.
Maakt de inspringbreedte uit bij het vergelijken van YAML?
Niet voor de betekenis, alleen voor de consistentie. YAML gebruikt inspringing om structuur te tonen, maar het maakt niet uit of je twee of vier spaties gebruikt, zolang elk niveau binnen het bestand consistent is. Dus een bestand met twee spaties en een met vier kunnen identieke data bevatten en toch totaal verschillend lijken voor een tekstdiff. Beide naar dezelfde breedte herformatteren verwijdert dat valse verschil. Tabs zijn echter helemaal niet toegestaan voor inspringing.
Hoe vergelijk ik YAML terwijl ik de sleutelvolgorde negeer?
YAML-mapping-sleutels zijn ongeordend, dus twee bestanden met dezelfde sleutels in een andere volgorde bevatten dezelfde data. Om een tekstdiff te laten instemmen, sorteer je de sleutels aan beide kanten voor het vergelijken. In de browser gebruik je de optie sleutels sorteren (canoniseren). Op de opdrachtregel doet yq het met sort_keys. Zodra beide bestanden de sleutels in dezelfde gesorteerde volgorde hebben, verschijnen alleen echte waardewijzigingen. Sequence-items blijven geordend, dus sorteer die niet.
Wat is het Noorwegen-probleem in YAML?
Het is een klassieke YAML-valkuil waarbij de ongeciteerde waarde NO als de boolean false wordt geparseerd in plaats van de string "NO", zodat een landcode voor Noorwegen false wordt. Het gebeurt in YAML 1.1-parsers, die yes, no, on en off als booleans behandelen. YAML 1.2 heeft de regels versmald, maar veel tools leveren nog 1.1-gedrag. Als een waarde in je diff lijkt te zijn omgeslagen van een woord naar true of false, is een ongeciteerde boolean-achtige string de waarschijnlijke oorzaak. De waarde tussen aanhalingstekens zetten lost het op.
Kan ik grote YAML-bestanden vergelijken zonder dat de pagina vastloopt?
Ja, tot op zekere hoogte. Een diff in regelmodus blijft snel op bestanden met duizenden regels omdat hij eerst hele regels vergelijkt in plaats van elk teken. Zeer grote bestanden (meerdere megabytes) kun je beter aanpakken met een opdrachtregeltool als yq of git diff, die de data streamt. Voor alles wat je comfortabel in een browser kunt scrollen, is een online diff de snellere optie.

Klaar om het te proberen? Plak je bestanden in de YAML-vergelijktool en zie wat er veranderde.