Jak porównać dwa pliki YAML bez kłopotów z wcięciami

Najszybszy sposób na porównanie dwóch plików YAML to wklejenie obu do narzędzia diff wyświetlającego je obok siebie, znormalizowanie wcięć i odczytanie wyróżnionych wierszy. Porównywanie to łatwa część. W YAML szum jest bardziej podstępny niż zwykle: zabłąkany tabulator, przestawiony klucz albo wartość, którą ktoś ujął w cudzysłów, mogą sprawić, że dwa pliki ładujące się do tych samych danych wyglądają, jakby nie miały nic wspólnego.

Ten przewodnik pokazuje, jak uzyskać czysty, wiarygodny diff YAML. Przyjrzymy się, dlaczego dwa równoważne pliki rozjeżdżają się na papierze, które metody warto znać i opracowanemu przykładowi, za którym możesz podążać. Jeśli chcesz tylko narzędzia, nasza strona porównywania YAML robi to wszystko w przeglądarce.

Dlaczego pliki YAML są zwodniczo trudne do porównania

YAML to format wrażliwy na białe znaki (zobacz specyfikację YAML 1.2.2), i właśnie to czyni diffy podchwytliwymi. Wcięcie niesie znaczenie, ale ilość wcięcia nie, dopóki jest spójna. Tak więc plik z wcięciem dwoma spacjami i inny z czterema mogą załadować się do identycznej struktury, podczas gdy każdy wiersz wygląda inaczej dla diffu tekstowego.

Oto kluczowy fakt, który trzeba zapamiętać: mapping YAML to zbiór par klucz/wartość i, podobnie jak obiekty JSON, kolejność tych kluczy nie zmienia danych. Więc to:

name: Ada Lovelace
role: editor

i to:

role: editor
name: Ada Lovelace

ładują się do tego samego mappingu, nawet jeśli diff wierszowy maluje je na czerwono i zielono. Elementy sekwencji są natomiast uporządkowane, więc przestawienie listy jest prawdziwą zmianą.

Wygląda na zmianę, ale zwykle nią nie jest
Co widzisz w diffieCzy to prawdziwa zmiana?Co zrobić
Wcięcie 2 vs 4 spacjeNie, liczy się tylko spójnośćSformatuj oba na tę samą szerokość
Klucze mappingu w innej kolejnościNie, mappingi są nieuporządkowanePosortuj klucze po obu stronach
true vs "true"Tak, boolean vs ciągZbadaj to, jest prawdziwe
name: Ada vs name: "Ada"Nie, ta sama wartość ciąguZnormalizuj cudzysłowy
Styl flow [a, b] vs lista blokowaNie, ta sama sekwencjaWybierz jeden styl dla obu
Elementy sekwencji w innej kolejnościTak, sekwencje są uporządkowaneZbadaj to, jest prawdziwe

Dwa wiersze tam to prawdziwe pułapki. true bez cudzysłowów to boolean; w cudzysłowach to ciąg "true", a to rozróżnienie spowodowało prawdziwe awarie. Ale name: Ada i name: "Ada" to ten sam ciąg. Jeśli chcesz szczegółów technicznych o tym, jak parser to rozstrzyga, sekcja specyfikacji o core schema jest punktem odniesienia.

Cztery sposoby porównywania YAML i kiedy po który sięgnąć

Nie ma jednej najlepszej metody. Zależy to od tego, gdzie są pliki i czego chcesz się dowiedzieć. Oto jak wypadają popularne opcje.

MetodaNajlepsza doWysiłekRozumie YAML?
Sprawdzanie wzrokiemMaleńkie pliki, jeden lub dwa kluczeNiskiNie, to ty jesteś parserem
Narzędzie diff onlineSzybkie sprawdzenia, wklejanie skądkolwiekNiskiZ formatowaniem, tak
Wiersz poleceń (yq)Pliki na dysku, skrypty, sortowanie kluczyŚredniTak, gdy najpierw posortujesz
IDE lub git diffPliki już w repozytoriumNiski, jeśli zacommitowaneDomyślnie wierszowo

Dla większości ludzi narzędzie w przeglądarce wygrywa szybkością: nic do instalowania, a fragment możesz wkleić wprost z manifestu Kubernetes lub konfiguracji CI. Haczykiem jest szum formatowania, którym zajmiemy się dalej. Jeśli żyjesz w terminalu, yq to narzędzie do nauki, a klucze potrafi sortować tak samo, jak jq robi to dla JSON.

Najszybsze czyste porównanie, krok po kroku

To rutyna, której używam, gdy ktoś podaje mi dwa manifesty i pyta „co się różni?". Zajmuje około piętnastu sekund.

  1. Otwórz narzędzie porównywania YAML.
  2. Wklej oryginał po lewej, a nową wersję po prawej.
  3. Kliknij Formatuj po obu stronach, aby miały to samo wcięcie.
  4. Włącz sortowanie kluczy, aby przestawione klucze mappingu przestały pojawiać się jako zmiany.
  5. Odczytaj wynik. Zielony to dodane, czerwony to usunięte, a zmieniona wartość pojawia się jako jeden z każdego koloru.

Kroki trzeci i czwarty to cała sztuczka. Gdy oba pliki używają tego samego wcięcia, a ich klucze są posortowane, jedyne, co zostaje do wyróżnienia, to to, co naprawdę się zmieniło. Nasz silnik diff opiera się na diff-match-patch od Google, który najpierw porównuje wiersz po wierszu, dzięki czemu pozostaje szybki nawet przy długich plikach.

Opracowany przykład

Powiedzmy, że przeglądasz zmianę w rekordzie użytkownika. Oto stan przed:

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

A oto stan po, tak jak przekazał ci go kolega z zespołu:

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

Wrzuć je do surowego diffu wierszowego, a wygląda, jakby prawie każdy wiersz się przesunął, bo klucze są w innej kolejności. Sformatuj i posortuj oba, a prawdziwa historia jest krótka:

Co naprawdę się zmieniło
KluczPrzedPoZmiana
roleeditoradminZmodyfikowano
seats35Zmodyfikowano
teamplatformDodano
nameAda LovelaceAda LovelaceBez zmian
activetruetrueBez zmian (tylko przeniesiono)

Trzy prawdziwe edycje: awans roli, liczba miejsc i nowy klucz zespołu. Przestawienie było szumem. Ten awans z editor na admin to dokładnie ten rodzaj rzeczy, który chcesz wychwycić w przeglądzie, a łatwo go przeoczyć, gdy jest pogrzebany pod fałszywymi alarmami.

Eliminowanie szumu formatowania w wierszu poleceń

Jeśli twoje pliki są już na dysku, ten sam pomysł „sformatuj i posortuj" działa z dwoma krótkimi poleceniami. yq potrafi posortować klucze i ponownie wyemitować formę kanoniczną, więc zwykły diff po tym jest uczciwy:

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

Teraz diff zgłasza tylko wartości, które naprawdę się zmieniły, bo oba pliki mają to samo wcięcie i tę samą kolejność kluczy. To terminalowy odpowiednik kliknięcia Formatuj i sortowania kluczy w przeglądarce.

Pułapki unikalne dla YAML

Kilka funkcji YAML powoduje diffy, które zaskakują ludzi. Anchors i aliases (&name i *name) pozwalają jednemu plikowi powtórzyć wartość przez referencję, podczas gdy inny wypisuje ją w całości; oba ładują się do tych samych danych, ale czytają się zupełnie inaczej. Niesławny „problem Norwegii" to kolejna: niecytowane no, off i yes mogą być parsowane jako booleany w starszych parserach YAML 1.1, więc country: NO może stać się false. YAML 1.2 naprawił schemat, ale wiele narzędzi nadal dostarcza zachowanie 1.1. Gdy wartość wygląda, jakby zmieniła typ, to pierwsza rzecz do sprawdzenia.

Częste pułapki, na które trzeba uważać

PułapkaDlaczego gryzieRozwiązanie
Tabulatory do wcięćYAML zabrania tabulatorów do wcięć; plik może się nawet nie sparsowaćNajpierw zamień tabulatory na spacje
Skalary z cudzysłowami i bez"true" to ciąg, true to booleanTo może być prawdziwa zmiana, nie lekceważ jej
Anchors i aliasesJeden plik wstawia wartość w miejscu, drugi się do niej odwołujeRozwiąż anchors, a potem porównaj rozwiniętą formę
Problem Norwegiino może być parsowane jako false w YAML 1.1Ujmij dwuznaczne ciągi w cudzysłów; sprawdź wersję parsera
Białe znaki na końcu wierszaNiewidoczne spacje po wartości pojawiają się jako zmianaPrzytnij końcowe białe znaki przed porównaniem

YAML i JSON są sobie bliższe, niż się wydaje

Każdy dokument JSON jest prawidłowym YAML, ponieważ YAML 1.2 to nadzbiór JSON. To przydatne do porównywania: jeśli wcięcia lub anchors dają ci się we znaki, przekonwertuj oba pliki na JSON, sformatuj je tak samo i porównaj to. Wiele parserów, w tym PyYAML, przeprowadza YAML w obie strony do prostej struktury danych, którą możesz ponownie wyemitować jako JSON, co zdziera różnice stylistyczne i zostawia same dane.

Powiązane narzędzia

YAML rzadko podróżuje sam. Jeśli porównujesz formę JSON tych samych danych, porównanie JSON stosuje ten sam pomysł. Ustawienia środowiska i pliki .env dobrze układają się na stronie porównania konfiguracji, a przeglądanie zmian między dwoma wywołaniami API to to, do czego zbudowano diff odpowiedzi API.

Najczęściej zadawane pytania

Czy porównywanie plików YAML online przesyła je gdziekolwiek?
Na comparetext.org diff działa w twojej przeglądarce. Dwa pliki YAML są porównywane przez JavaScript na twoim własnym komputerze, więc nic nie jest wysyłane na serwer, dopóki wyraźnie nie klikniesz Zapisz lub Udostępnij. To czyni go bezpiecznym dla manifestów Kubernetes, konfiguracji CI i innych danych, których nie chciałbyś wklejać na stronę przesyłającą wszystko przy każdym naciśnięciu klawisza.
Dlaczego moje dwa pliki YAML pokazują każdy wiersz jako różny?
Niemal zawsze to formatowanie, a nie prawdziwe zmiany. Jeden plik ma wcięcie dwoma spacjami, drugi czterema, albo klucze mappingu są w innej kolejności, albo jeden używa cudzysłowów, a drugi nie. Sformatuj obie strony do tego samego wcięcia i posortuj klucze, aby kolejność przestała mieć znaczenie. Po tym diff zwykle kurczy się do garstki wartości, które naprawdę się zmieniły.
Czy szerokość wcięcia ma znaczenie przy porównywaniu YAML?
Nie dla znaczenia, tylko dla spójności. YAML używa wcięcia, by pokazać strukturę, ale nie obchodzi go, czy używasz dwóch czy czterech spacji, dopóki każdy poziom jest spójny w obrębie pliku. Tak więc plik z dwiema spacjami i plik z czterema mogą zawierać identyczne dane, a mimo to wyglądać zupełnie inaczej dla diffu tekstowego. Sformatowanie obu do tej samej szerokości usuwa tę fałszywą różnicę. Tabulatory natomiast nie są w ogóle dozwolone do wcięć.
Jak porównać YAML, ignorując kolejność kluczy?
Klucze mappingu YAML są nieuporządkowane, więc dwa pliki z tymi samymi kluczami w innej kolejności zawierają te same dane. Aby diff tekstowy się z tym zgodził, posortuj klucze po obu stronach przed porównaniem. W przeglądarce użyj opcji sortowania kluczy (kanonizacja). W wierszu poleceń yq robi to z sort_keys. Gdy oba pliki mają klucze w tej samej posortowanej kolejności, pojawiają się tylko prawdziwe zmiany wartości. Elementy sekwencji zachowują kolejność, więc ich nie sortuj.
Czym jest problem Norwegii w YAML?
To klasyczna pułapka YAML, w której niecytowana wartość NO jest parsowana jako boolean false zamiast ciągu "NO", więc kod kraju dla Norwegii staje się false. Dzieje się to w parserach YAML 1.1, które traktują yes, no, on i off jako booleany. YAML 1.2 zawęził reguły, ale wiele narzędzi nadal dostarcza zachowanie 1.1. Jeśli wartość wygląda, jakby zmieniła się ze słowa na true lub false w twoim diffie, niecytowany ciąg podobny do boolean jest prawdopodobną przyczyną. Ujęcie wartości w cudzysłów to naprawia.
Czy mogę porównywać duże pliki YAML bez zawieszania strony?
Tak, do pewnego stopnia. Diff w trybie wierszowym pozostaje szybki przy plikach z tysiącami wierszy, bo najpierw porównuje całe wiersze, a nie każdy znak. Bardzo duże pliki (kilka megabajtów) lepiej obsłużyć narzędziem wiersza poleceń, jak yq lub git diff, które strumieniuje dane. Dla wszystkiego, co da się wygodnie przewinąć w przeglądarce, diff online jest szybszą opcją.

Gotów spróbować? Wklej swoje pliki do narzędzia porównywania YAML i zobacz, co się zmieniło.