Jak zignorować przesunięte linie w diff

11

Obecnie pracuję nad narzędziem do generowania kodu źródłowego. Aby upewnić się, że moje zmiany nie wprowadzają żadnych nowych błędów, diffteoretycznie cennym narzędziem byłoby między wyjściem programu przed i po moich zmianach.

Jednak okazuje się to trudniejsze niż mogłoby się wydawać, ponieważ narzędzie wypisuje wiersze, w których kolejność nie ma znaczenia (np. importInstrukcje, deklaracje funkcji,…) w sposób pół losowo uporządkowany. Z tego powodu wynik diffjest zaśmiecony wieloma zmianami, które w rzeczywistości są tylko liniami przeniesionymi do innej pozycji w tym samym pliku.

Czy istnieje sposób, aby diff ignorował te ruchy i wyświetlał tylko te wiersze, które naprawdę zostały dodane lub usunięte?

dnadlinger
źródło
Może łatwiej jest zmienić narzędzie do generowania funkcji i importowania deklaracji w określonej kolejności (np. Leksykograficznej, jeśli to możliwe w twoim języku)?
Daniel Beck
@Daniel Beck: Zobacz mój komentarz do odpowiedzi Gillesa poniżej.
dnadlinger,
Stary temat, ale podsumowując komentarze poniżej, w jaki sposób to diffnarzędzie byłoby w stanie oddzielić prawidłowe przeniesienia od niepoprawnych, ponieważ kolejność instrukcji w kodzie ma znaczenie, a przypadki, w których nie jest to prawdą, są ograniczone (import, deklaracja funkcji i klas, itp.)?
Joël
@ Joël: Odpowiedź jest prosta: wiedziałem, że zmiany generatora, które musiałem przetestować, nie wprowadziłyby żadnych błędów związanych ze zmianą kolejności linii. Oczywiście potrzebujesz narzędzia opartego na parserze dla języka docelowego, aby uniknąć fałszywych alarmów w ogólnym przypadku (lub po prostu kompleksowego zestawu testów dla twojego generatora), ale miał to być również szybki jednorazowy test do przeglądu kodu.
dnadlinger,

Odpowiedzi:

2

Możesz zrobić prosty diff, zapisać gdzieś wynik (aby uniknąć innego diff), zapętlić linie w obu wersjach, a następnie usunąć je z drugiej strony.

Spowodowało to powstanie osobnego projektu dla działającego kodu. Kod.

l0b0
źródło
Nie jestem pewien, co dokładnie powinno to zrobić, ale wydaje się, że nie przynosi oczekiwanych rezultatów. Jak rozumiem pytanie, z dwóch przykładów w kodzie /tmp/oldi /tmp/newżadnych różnic nie byłby pożądany, ponieważ zostały przeniesione tylko linie. Ten kod daje jednak wyniki.
Ilari Kajaste
Naprawiono kod.
l0b0
Nie testowałem odpowiedzi, ponieważ już dawno skończyłem proces scalania, o którym mowa powyżej, ale na pierwszy rzut oka wygląda na to, że mógłby zadziałać.
dnadlinger,
4

Najpierw możesz spróbować je posortować. Coś jak:

sort file-a > s-file-a
sort file-b > s-file-b
diff s-file-a s-file-b

Bash (i zsh) może to zrobić w jednym wierszu z podstawieniem procesu

diff <(sort file-a) <(sort file-b)
Cyrus
źródło
Może to być opcja, ale wygenerowane różnice nie byłyby wtedy bardzo przydatne, ponieważ straciłbym cały numer linii i informacje kontekstowe…
dnadlinger
Nawet jeśli wciąż mam nadzieję na lepsze rozwiązanie, zastosowałem to podejście do weryfikacji partii zmian, nad którymi pracowałem.
dnadlinger,
2
Mogę przewidzieć, gdzie to pominąłoby niektóre zmiany. Czasami zamówienie ma znaczenie, a czasem nie. Odrzucasz cały kontekst.
Rich Homolka
Dla refaktora zamawiającego, w którym chciałem się upewnić, że wszystko, co istniało, nadal działa, właśnie tego potrzebowałem.
ntrrobng
0

Wygląda na to, że masz kontrolę nad narzędziem. Następnie spraw, aby jego wynik był przewidywalny: zamiast emitować deklaracje w pół losowej kolejności, użyj (powiedzmy) kolejności alfabetycznej w ostateczności. Przyniesie to nie tylko korzyść polegającą na usunięciu bezużytecznego crufta z różnic, ale także na ułatwieniu odczytania i weryfikacji wyników narzędzia przez człowieka.

Gilles „SO- przestań być zły”
źródło
Przepraszam, ale ta odpowiedź w ogóle mi nie pomaga - gdybym była taka łatwa, od razu bym ją zmieniła. Ponadto łączę obecnie zmiany z projektu, z którego pierwotnie opracowano generator, więc dodanie tak daleko idącej zmiany skomplikowałoby ten proces jeszcze bardziej…
dnadlinger
0

Jeśli plik jest podzielony na sekcje, to tylko sekcje są nie w porządku, a istnieje wyrażenie regularne, którego można użyć do rozpoznania nagłówka sekcji, możesz umieścić pliki w sekcjach i porównać sekcje w parach.

Na przykład, właśnie to zrobiłem na dwóch zrzutach MySQL, aby porównać je po zmianie wielkości nazw niektórych baz danych (dlatego zrzut pokazał je w innej kolejności):

csplit all-07sep2015-11:19:12.sql '/Current Database/-1' '{*}'  # split the dump made before the change, creating files xx00, xx01, ...
csplit -f yy all-07sep2015-12:26:12.sql '/Current Database/-1' '{*}' # split the dump made after the change, creating files yy00, yy01, ...
fgrep 'Current Database' xx?? yy?? | perl -lne 'BEGIN{my %foo}; /(^....).*`(.*)`/ and push(@{$foo{lc($2)}}, $1); END {printf("diff -di %s %s\n", @{$_}) for values %foo}' | sh -x | less  # match the pairs and compare them with diff
reinierpost
źródło