Sådan sammenligner du to YAML-filer uden at falde over indrykning

Den hurtigste måde at sammenligne to YAML-filer på er at indsætte begge i et diff-værktøj, der viser dem side om side, normalisere indrykningen og læse de linjer, det fremhæver. Sammenligningen er den nemme del. Med YAML er støjen mere lumsk end normalt: en forvildet tabulator, en ombyttet nøgle eller en værdi, som nogen satte i anførselstegn, kan få to filer, der indlæses til samme data, til at se ud, som om de intet har til fælles.

Denne guide gennemgår, hvordan du får en ren, pålidelig YAML-diff. Vi ser på, hvorfor to ækvivalente filer driver fra hinanden på papiret, hvilke metoder der er værd at kende, og et gennemarbejdet eksempel, du kan følge. Hvis du bare vil have værktøjet, gør vores YAML-sammenligningsside alt dette i browseren.

Hvorfor YAML-filer er bedragerisk svære at sammenligne

YAML er et format, der er følsomt over for mellemrum (se YAML 1.2.2-specifikationen), og det er netop det, der gør diffs vanskelige. Indrykning bærer mening, men mængden af indrykning gør det ikke, så længe den er konsekvent. Så en fil indrykket med to mellemrum og en anden med fire kan indlæses til identisk struktur, mens hver linje ser forskellig ud for en tekstdiff.

Her er den vigtige kendsgerning at holde fast i: en YAML-mapping er et sæt nøgle/værdi-par, og ligesom JSON-objekter ændrer rækkefølgen af disse nøgler ikke dataene. Så dette:

name: Ada Lovelace
role: editor

og dette:

role: editor
name: Ada Lovelace

indlæses til samme mapping, selvom en linjediff maler dem røde og grønne. Sekvenselementer er derimod ordnede, så at flytte om på en liste er en reel ændring.

Ligner en ændring, er det som regel ikke
Hvad du ser i diffenEr det en reel ændring?Hvad du gør
2 vs 4 mellemrums indrykningNej, kun konsekvens betyder nogetOmformatér begge til samme bredde
Mapping-nøgler i en anden rækkefølgeNej, mappings er uordnedeSortér nøgler på begge sider
true vs "true"Ja, boolean vs strengUndersøg det, dette er reelt
name: Ada vs name: "Ada"Nej, samme strengværdiNormalisér anførselstegn
Flow-stil [a, b] vs bloklisteNej, samme sekvensVælg én stil for begge
Sekvenselementer i en anden rækkefølgeJa, sekvenser er ordnedeUndersøg det, dette er reelt

To rækker der er ægte fælder. true uden anførselstegn er en boolean; med anførselstegn er det strengen "true", og den skelnen har forårsaget reelle nedbrud. Men name: Ada og name: "Ada" er den samme streng. Hvis du vil have de tekniske detaljer om, hvordan en parser løser dette, er specifikationens afsnit om core schema referencen.

Fire måder at sammenligne YAML på, og hvornår du skal gribe til hver

Der er ingen enkelt bedste metode. Det afhænger af, hvor filerne er, og hvad du forsøger at finde ud af. Sådan står de almindelige muligheder.

MetodeBedst tilIndsatsForstår YAML?
At se det med øjetBittesmå filer, en eller to nøglerLavNej, du er parseren
Online diff-værktøjHurtige tjek, indsæt fra hvor som helstLavMed omformatering, ja
Kommandolinje (yq)Filer på disk, scripting, sortering af nøglerMellemJa, når du sorterer først
IDE eller git diffFiler allerede i et repoLav hvis committetLinjebaseret som standard

For de fleste vinder et browserværktøj på hastighed: intet at installere, og du kan indsætte et fragment direkte fra et Kubernetes-manifest eller en CI-konfiguration. Hagen er formateringsstøj, som vi tager fat på næste gang. Hvis du lever i terminalen, er yq værktøjet at lære, og det kan sortere nøgler på samme måde, som jq gør for JSON.

Den hurtigste rene sammenligning, trin for trin

Dette er den rutine, jeg bruger, når nogen rækker mig to manifester og spørger "hvad er forskellen?". Det tager omkring femten sekunder.

  1. Åbn YAML-sammenligningsværktøjet.
  2. Indsæt originalen til venstre, den nye version til højre.
  3. Klik på Formatér på begge sider, så de deler samme indrykning.
  4. Slå sortér nøgler til, så ombyttede mapping-nøgler holder op med at dukke op som ændringer.
  5. Læs resultatet. Grøn er tilføjet, rød er fjernet, og en ændret værdi vises som én af hver.

Trin tre og fire er hele tricket. Når begge filer bruger samme indrykning, og deres nøgler er sorteret, er det eneste, der er tilbage at fremhæve, det, der faktisk er ændret. Vores diff-motor er bygget på Googles diff-match-patch, som sammenligner linje for linje først, så den forbliver hurtig selv på lange filer.

Et gennemarbejdet eksempel

Lad os sige, at du gennemgår en ændring i en brugerpost. Her er før:

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

Og her er efter, som en kollega rakte dig den:

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

Smid dem ind i en rå linjediff, og det ser ud, som om næsten hver linje er flyttet, fordi nøglerne er i en anden rækkefølge. Omformatér og sortér begge, og den reelle historie er kort:

Hvad der faktisk blev ændret
NøgleFørEfterÆndring
roleeditoradminÆndret
seats35Ændret
teamplatformTilføjet
nameAda LovelaceAda LovelaceIngen ændring
activetruetrueIngen ændring (kun flyttet)

Tre reelle redigeringer: en rolleopgradering, et pladsantal og en ny team-nøgle. Ombytningen var støj. Den opgradering fra editor til admin er præcis den slags ting, du vil fange i en gennemgang, og den er nem at overse, når den er begravet under falske alarmer.

At dræbe formateringsstøjen på kommandolinjen

Hvis dine filer allerede er på disk, fungerer den samme "omformatér og sortér"-idé med to korte kommandoer. yq kan sortere nøgler og genudsende en kanonisk form, så en almindelig diff bagefter er ærlig:

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 rapporterer diff kun værdier, der virkelig er ændret, fordi begge filer har samme indrykning og samme nøglerækkefølge. Dette er terminalækvivalenten til at klikke på Formatér og sortér nøgler i browseren.

Fælderne, der er unikke for YAML

Nogle få YAML-funktioner forårsager diffs, der overrasker folk. Anchors og aliases (&name og *name) lader én fil gentage en værdi via reference, mens en anden skriver den ud i sin helhed; begge indlæses til samme data, men læses helt forskelligt. Det berygtede "Norge-problem" er et andet: ucitérede no, off og yes kan fortolkes som booleans i ældre YAML 1.1-parsere, så country: NO kan blive false. YAML 1.2 rettede skemaet, men mange værktøjer leverer stadig 1.1-adfærd. Når en værdi ser ud til at have skiftet type, er det det første, du skal tjekke.

Almindelige faldgruber at holde øje med

FaldgrubeHvorfor den biderLøsning
Tabulatorer til indrykningYAML forbyder tabulatorer til indrykning; filen kan måske ikke engang parsesKonvertér tabulatorer til mellemrum først
Citérede vs ucitérede skalarer"true" er en streng, true er en booleanDette kan være en reel ændring, afvis den ikke
Anchors og aliasesÉn fil indsætter en værdi inline, den anden refererer til denLøs anchors op, sammenlign så den udvidede form
Norge-problemetno kan fortolkes som false i YAML 1.1Citér tvetydige strenge; tjek din parserversion
Efterfølgende mellemrumUsynlige mellemrum efter en værdi vises som en ændringTrim efterfølgende mellemrum før sammenligning

YAML og JSON er tættere på hinanden, end de ser ud

Hvert JSON-dokument er gyldig YAML, fordi YAML 1.2 er et supersæt af JSON. Det er praktisk til sammenligning: hvis indrykningen eller anchors driller dig, konvertér begge filer til JSON, formatér dem på samme måde, og diff det i stedet. Mange parsere, inklusive PyYAML, kører YAML frem og tilbage til en simpel datastruktur, du kan genudsende som JSON, hvilket fjerner de stilistiske forskelle og kun efterlader dataene.

Relaterede værktøjer

YAML rejser sjældent alene. Hvis du sammenligner JSON-formen af de samme data, anvender JSON-sammenligning den samme idé. Miljøindstillinger og .env-filer stiller sig pænt op på siden for konfigurationssammenligning, og at gennemgå ændringer mellem to API-kald er, hvad API-svardiffen er bygget til.

Ofte stillede spørgsmål

Uploader sammenligning af YAML-filer online dem nogen steder?
På comparetext.org kører diffen i din browser. De to YAML-filer sammenlignes af JavaScript på din egen maskine, så intet sendes til en server, medmindre du udtrykkeligt klikker på Gem eller Del. Det gør det sikkert for Kubernetes-manifester, CI-konfigurationer og andre data, du ikke ville ønske at indsætte på en side, der uploader ved hvert tastetryk.
Hvorfor viser mine to YAML-filer hver linje som forskellig?
Næsten altid er det formatering, ikke reelle ændringer. Én fil er indrykket med to mellemrum, den anden med fire, eller mapping-nøglerne er i en anden rækkefølge, eller én bruger anførselstegn og den anden ikke. Omformatér begge sider til samme indrykning og sortér nøglerne, så rækkefølgen holder op med at betyde noget. Derefter krymper diffen som regel til den håndfuld værdier, der reelt er ændret.
Betyder indrykningsbredde noget ved sammenligning af YAML?
Ikke for betydningen, kun for konsekvensen. YAML bruger indrykning til at vise struktur, men er ligeglad med, om du bruger to eller fire mellemrum, så længe hvert niveau er konsekvent inden for filen. Så en fil med to mellemrum og en fil med fire kan indeholde identiske data, mens de ser helt forskellige ud for en tekstdiff. At omformatere begge til samme bredde fjerner den falske forskel. Tabulatorer er derimod slet ikke tilladt til indrykning.
Hvordan sammenligner jeg YAML, mens jeg ignorerer nøglerækkefølge?
YAML-mapping-nøgler er uordnede, så to filer med samme nøgler i en anden rækkefølge indeholder de samme data. For at en tekstdiff skal være enig, sortér nøglerne på begge sider før sammenligning. I browseren bruger du muligheden sortér nøgler (kanonisér). På kommandolinjen gør yq det med sort_keys. Når begge filer har nøgler i samme sorterede rækkefølge, vises kun reelle værdiændringer. Sekvenselementer bevarer rækkefølgen, så sortér ikke dem.
Hvad er Norge-problemet i YAML?
Det er en klassisk YAML-fælde, hvor den ucitérede værdi NO fortolkes som booleanen false i stedet for strengen "NO", så en landekode for Norge bliver false. Det sker i YAML 1.1-parsere, som behandler yes, no, on og off som booleans. YAML 1.2 indsnævrede reglerne, men mange værktøjer leverer stadig 1.1-adfærd. Hvis en værdi ser ud til at være vendt fra et ord til true eller false i din diff, er en ucitéret boolean-lignende streng den sandsynlige årsag. At citere værdien retter det.
Kan jeg sammenligne store YAML-filer uden at siden fryser?
Ja, op til et vist punkt. En diff i linjetilstand forbliver hurtig på filer med tusindvis af linjer, fordi den sammenligner hele linjer først i stedet for hvert tegn. Meget store filer (flere megabyte) håndteres bedre med et kommandolinjeværktøj som yq eller git diff, som streamer dataene. For alt, du komfortabelt kan scrolle igennem i en browser, er en online-diff den hurtigere mulighed.

Klar til at prøve det? Indsæt dine filer i YAML-sammenligningsværktøjet og se, hvad der er ændret.