Slik sammenligner du to YAML-filer uten å snuble i innrykk

Den raskeste måten å sammenligne to YAML-filer på er å lime inn begge i et diff-verktøy som viser dem side om side, normalisere innrykket og lese linjene det fremhever. Sammenligningen er den enkle delen. Med YAML er støyen lurere enn vanlig: en forvillet tabulator, en ombyttet nøkkel eller en verdi som noen satte i anførselstegn, kan få to filer som lastes til samme data til å se ut som om de ikke har noe til felles.

Denne guiden går gjennom hvordan du får en ren, pålitelig YAML-diff. Vi ser på hvorfor to likeverdige filer driver fra hverandre på papiret, hvilke metoder som er verdt å kunne, og et gjennomarbeidet eksempel du kan følge. Hvis du bare vil ha verktøyet, gjør vår YAML-sammenligningsside alt dette i nettleseren.

Hvorfor YAML-filer er bedragersk vanskelige å sammenligne

YAML er et format som er følsomt for blanktegn (se YAML 1.2.2-spesifikasjonen), og det er nettopp det som gjør differ vanskelige. Innrykk bærer mening, men mengden innrykk gjør det ikke, så lenge den er konsekvent. Så en fil innrykket med to mellomrom og en annen med fire kan lastes til identisk struktur mens hver linje ser forskjellig ut for en tekstdiff.

Her er det viktige å holde fast ved: en YAML-mapping er et sett med nøkkel/verdi-par, og som JSON-objekter endrer ikke rekkefølgen på disse nøklene dataene. Så dette:

name: Ada Lovelace
role: editor

og dette:

role: editor
name: Ada Lovelace

lastes til samme mapping, selv om en linjediff maler dem røde og grønne. Sekvenselementer er derimot ordnet, så å bytte om en liste er en reell endring.

Ser ut som en endring, er det vanligvis ikke
Hva du ser i diffenEr det en reell endring?Hva du gjør
2 vs 4 mellomroms innrykkNei, bare konsekvens betyr noeReformater begge til samme bredde
Mapping-nøkler i en annen rekkefølgeNei, mappinger er uordnedeSorter nøkler på begge sider
true vs "true"Ja, boolean vs strengUndersøk det, dette er reelt
name: Ada vs name: "Ada"Nei, samme strengverdiNormaliser anførselstegn
Flytstil [a, b] vs blokklisteNei, samme sekvensVelg én stil for begge
Sekvenselementer i en annen rekkefølgeJa, sekvenser er ordnetUndersøk det, dette er reelt

To rader der er ekte feller. true uten anførselstegn er en boolean; med anførselstegn er det strengen "true", og det skillet har forårsaket reelle nedetider. Men name: Ada og name: "Ada" er den samme strengen. Hvis du vil ha de tekniske detaljene om hvordan en parser løser dette, er spesifikasjonens avsnitt om core schema referansen.

Fire måter å sammenligne YAML på, og når du skal gripe til hver

Det finnes ingen enkelt beste metode. Det avhenger av hvor filene er, og hva du prøver å finne ut. Slik står de vanlige alternativene.

MetodeBest forInnsatsForstår YAML?
Å se det med øyetBittesmå filer, én eller to nøklerLavNei, du er parseren
Online diff-verktøyRaske sjekker, lim inn fra hvor som helstLavMed reformatering, ja
Kommandolinje (yq)Filer på disk, skripting, sortering av nøklerMiddelsJa, når du sorterer først
IDE eller git diffFiler allerede i et repoLav hvis committetLinjebasert som standard

For de fleste vinner et nettleserverktøy på hastighet: ingenting å installere, og du kan lime inn et fragment rett fra et Kubernetes-manifest eller en CI-konfigurasjon. Haken er formateringsstøy, som vi tar tak i neste gang. Hvis du lever i terminalen, er yq verktøyet å lære, og det kan sortere nøkler på samme måte som jq gjør for JSON.

Den raskeste rene sammenligningen, steg for steg

Dette er rutinen jeg bruker når noen rekker meg to manifester og spør "hva er forskjellen?". Det tar omtrent femten sekunder.

  1. Åpne YAML-sammenligningsverktøyet.
  2. Lim inn originalen til venstre, den nye versjonen til høyre.
  3. Klikk på Formater på begge sider så de deler samme innrykk.
  4. Slå på sorter nøkler så ombyttede mapping-nøkler slutter å dukke opp som endringer.
  5. Les resultatet. Grønt er lagt til, rødt er fjernet, og en endret verdi vises som én av hver.

Steg tre og fire er hele trikset. Når begge filene bruker samme innrykk og nøklene deres er sortert, er det eneste som gjenstår å fremheve det som faktisk er endret. Diff-motoren vår er bygget på Googles diff-match-patch, som sammenligner linje for linje først, så den forblir rask selv på lange filer.

Et gjennomarbeidet eksempel

La oss si at du gjennomgår en endring i en brukerpost. Her er før:

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

Og her er etter, slik en kollega rakte den til deg:

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

Slipp dem inn i en rå linjediff, og det ser ut som om nesten hver linje har flyttet seg, fordi nøklene er i en annen rekkefølge. Reformater og sorter begge, og den reelle historien er kort:

Hva som faktisk ble endret
NøkkelFørEtterEndring
roleeditoradminEndret
seats35Endret
teamplatformLagt til
nameAda LovelaceAda LovelaceIngen endring
activetruetrueIngen endring (bare flyttet)

Tre reelle endringer: en rolleopprykk, et seteantall og en ny team-nøkkel. Ombyttingen var støy. Det opprykket fra editor til admin er nøyaktig den typen ting du vil fange i en gjennomgang, og det er lett å overse når det er begravd under falske alarmer.

Å drepe formateringsstøyen på kommandolinjen

Hvis filene dine allerede er på disk, fungerer den samme "reformater og sorter"-ideen med to korte kommandoer. yq kan sortere nøkler og sende ut en kanonisk form på nytt, så en vanlig diff etterpå 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

Nå rapporterer diff bare verdier som virkelig er endret, fordi begge filene har samme innrykk og samme nøkkelrekkefølge. Dette er terminalekvivalenten til å klikke på Formater og sorter nøkler i nettleseren.

Fellene som er unike for YAML

Noen få YAML-funksjoner forårsaker differ som overrasker folk. Anchors og aliases (&name og *name) lar én fil gjenta en verdi via referanse mens en annen skriver den ut i sin helhet; begge lastes til samme data, men leses helt forskjellig. Det beryktede "Norge-problemet" er et annet: usiterte no, off og yes kan tolkes som booleans i eldre YAML 1.1-parsere, så country: NO kan bli false. YAML 1.2 fikset skjemaet, men mange verktøy leverer fortsatt 1.1-oppførsel. Når en verdi ser ut til å ha byttet type, er det det første du bør sjekke.

Vanlige fallgruver å se opp for

FallgruveHvorfor den biterLøsning
Tabulatorer til innrykkYAML forbyr tabulatorer til innrykk; filen blir kanskje ikke engang parsetKonverter tabulatorer til mellomrom først
Siterte vs usiterte skalarer"true" er en streng, true er en booleanDette kan være en reell endring, ikke avfei den
Anchors og aliasesÉn fil setter inn en verdi inline, den andre refererer til denLøs opp anchors, sammenlign så den utvidede formen
Norge-problemetno kan tolkes som false i YAML 1.1Siter tvetydige strenger; sjekk parserversjonen din
Etterfølgende blanktegnUsynlige mellomrom etter en verdi vises som en endringTrim etterfølgende blanktegn før sammenligning

YAML og JSON er nærmere hverandre enn de ser ut

Hvert JSON-dokument er gyldig YAML, fordi YAML 1.2 er et supersett av JSON. Det er praktisk for sammenligning: hvis innrykket eller anchors plager deg, konverter begge filene til JSON, formater dem på samme måte, og diff det i stedet. Mange parsere, inkludert PyYAML, kjører YAML frem og tilbake til en enkel datastruktur du kan sende ut på nytt som JSON, noe som fjerner de stilistiske forskjellene og etterlater bare dataene.

Relaterte verktøy

YAML reiser sjelden alene. Hvis du sammenligner JSON-formen av de samme dataene, bruker JSON-sammenligning den samme ideen. Miljøinnstillinger og .env-filer stiller seg pent opp på siden for konfigurasjonssammenligning, og å gjennomgå endringer mellom to API-kall er det API-svardiffen er bygget for.

Ofte stilte spørsmål

Laster sammenligning av YAML-filer online dem opp noe sted?
På comparetext.org kjører diffen i nettleseren din. De to YAML-filene sammenlignes av JavaScript på din egen maskin, så ingenting sendes til en server med mindre du eksplisitt klikker på Lagre eller Del. Det gjør det trygt for Kubernetes-manifester, CI-konfigurasjoner og andre data du ikke ville ønsket å lime inn på et nettsted som laster opp ved hvert tastetrykk.
Hvorfor viser de to YAML-filene mine hver linje som forskjellig?
Nesten alltid er det formatering, ikke reelle endringer. Én fil er innrykket med to mellomrom, den andre med fire, eller mapping-nøklene er i en annen rekkefølge, eller én bruker anførselstegn og den andre ikke. Reformater begge sider til samme innrykk og sorter nøklene så rekkefølgen slutter å bety noe. Etter det krymper diffen vanligvis til den håndfullen verdier som virkelig er endret.
Betyr innrykksbredde noe ved sammenligning av YAML?
Ikke for betydningen, bare for konsekvensen. YAML bruker innrykk til å vise struktur, men bryr seg ikke om du bruker to eller fire mellomrom, så lenge hvert nivå er konsekvent innenfor filen. Så en fil med to mellomrom og en fil med fire kan inneholde identiske data mens de ser helt forskjellige ut for en tekstdiff. Å reformatere begge til samme bredde fjerner den falske forskjellen. Tabulatorer er derimot ikke tillatt til innrykk i det hele tatt.
Hvordan sammenligner jeg YAML mens jeg ignorerer nøkkelrekkefølge?
YAML-mapping-nøkler er uordnede, så to filer med samme nøkler i en annen rekkefølge inneholder de samme dataene. For at en tekstdiff skal være enig, sorter nøklene på begge sider før sammenligning. I nettleseren bruker du alternativet sorter nøkler (kanonisering). På kommandolinjen gjør yq det med sort_keys. Når begge filene har nøkler i samme sorterte rekkefølge, vises bare reelle verdiendringer. Sekvenselementer beholder rekkefølgen, så ikke sorter dem.
Hva er Norge-problemet i YAML?
Det er en klassisk YAML-felle der den usiterte verdien NO tolkes som booleanen false i stedet for strengen "NO", så en landkode for Norge blir false. Det skjer i YAML 1.1-parsere, som behandler yes, no, on og off som booleans. YAML 1.2 snevret inn reglene, men mange verktøy leverer fortsatt 1.1-oppførsel. Hvis en verdi ser ut til å ha snudd fra et ord til true eller false i diffen din, er en usitert boolean-lignende streng den sannsynlige årsaken. Å sitere verdien fikser det.
Kan jeg sammenligne store YAML-filer uten at siden fryser?
Ja, opp til et visst punkt. En diff i linjemodus forblir rask på filer med tusenvis av linjer fordi den sammenligner hele linjer først i stedet for hvert tegn. Svært store filer (flere megabyte) håndteres bedre med et kommandolinjeverktøy som yq eller git diff, som strømmer dataene. For alt du komfortabelt kan scrolle gjennom i en nettleser, er en online-diff det raskere alternativet.

Klar til å prøve det? Lim inn filene dine i YAML-sammenligningsverktøyet og se hva som er endret.