Dif

Aktuální verze stránky ještě nebyla zkontrolována zkušenými přispěvateli a může se výrazně lišit od verze recenzované 14. března 2022; kontroly vyžadují 2 úpravy .

V oblasti výpočetní techniky je  diff nástroj pro porovnání souborů, který zobrazuje rozdíl mezi dvěma soubory. Tento program vytiskne řádek po řádku změny provedené v souboru (u textových souborů). Moderní implementace také podporují binární . Výstup obslužného programu se nazývá „diff“ nebo častěji patch , protože jej lze aplikovat pomocí programu patch . Výstup jiných nástrojů pro porovnávání souborů je také často označován jako "diff".

Historie

Nástroj diff byl vyvinut na počátku 70. let pro operační systém Unix , který byl dílem laboratoří AT&T Bell Labs v Murray Hill, New Jersey. Finální verzi, distribuovanou s Unixem 5 v roce 1974, napsal výhradně Douglas McIlroy .

McIlroyově práci předcházel a ovlivňoval srovnávací program GECOS Steva Johnsona a důkazový program Mikea Leska. Důkaz také vznikl v Unixu a stejně jako diff prováděl změny řádek po řádku a dokonce používal lomené závorky (">" a "<") k reprezentaci vkládání a mazání řádků ve výstupu programu. Avšak heuristika použitá v těchto raných aplikacích byla považována za nespolehlivou. Potenciální užitečnost srovnávacího nástroje vyprovokovala McIlroye k výzkumu a vývoji robustnějšího nástroje, který by mohl být použit v různých úkolech, ale který by dobře fungoval v rámci omezení zpracování a velikosti hardwaru PDP-11. Jeho přístup k problému byl výsledkem spolupráce s lidmi z Bell Labs, včetně Alfreda Aha, Elliota Pinsona, Jeffreyho Ullmana a Harolda S. Stonea.

Algoritmus

Operace diff je založena na nalezení nejdelší společné podsekvence ( problém LCS) .  Například existují dvě sekvence prvků:

abcdfghjqz abcdefgijkrxyz

a musíte najít nejdelší sekvenci prvků, která je uvedena v obou sekvencích ve stejném pořadí. To znamená, že je nutné najít novou sekvenci, kterou lze získat z první sekvence smazáním některých prvků nebo z druhé sekvence vymazáním dalších prvků. V tomto případě bude sekvence

abcdfgjz

Po získání největší společné sekvence zbývá jen malý krok, než získáte výstup podobný rozdílu:

ehikqrxy + - + + - + + +

Použití

diff se volá z příkazového řádku s názvy dvou souborů jako argumenty: diff original new . Výstupem příkazu jsou změny, které je třeba provést v původním zdrojovém souboru, aby byl nový soubor nový. Pokud jsou původní a nové adresáře, pak se rozdíl automaticky použije na každý soubor, který existuje v obou adresářích. Všechny příklady v tomto článku používají následující dva soubory, původní a nový :

originál:

Tato část dokumentu zůstal nezměněn od verze k verzi. Pokud není u ní žádná změna by se nemělo zobrazovat. Jinak to nepomáhá závěr optimální vyrobeno Změny. Tento odstavec obsahuje zastaralý text. Bude odstraněn již brzy. Tento dokument musí být Kontrola pravopisu. Na druhou stranu chyba jedním slovem - ne konec světa. Zbytek odstavce nevyžaduje změny. Nový text může přidat na konec dokumentu.

Nový:

Toto je důležitá poznámka! Proto by mělo nacházet se na začátku tohoto dokument! Tato část dokumentu zůstal nezměněn od verze k verzi. Pokud není u ní žádná změna by se nemělo zobrazovat. Jinak to nepomáhá závěr optimální množství informací. Tento dokument musí být Kontrola pravopisu. Na druhou stranu chyba jedním slovem - ne konec světa. Zbytek odstavce nevyžaduje změny. Nový text může přidat na konec dokumentu. Tento odstavec obsahuje důležité doplňky pro tento dokument.

Původní nový příkaz diff vytváří následující normální výstup diff :

0a1.6 > Toto je důležitá poznámka! > Proto by mělo > být lokalizován > na začátku tohoto > dokument! > 8.14c14 < objem vyrobeného < změny. < < Tento odstavec obsahuje < zastaralý text. < Bude smazáno < v blízké budoucnosti. --- > množství informací. 17c17 < je třeba udělat --- > je třeba udělat 24a25.28 > > Tento odstavec obsahuje > důležité doplňky > pro tento dokument.

V tomto tradičním výstupním formátu a znamená přidáno (z anglického  add ), d znamená odstraněno , c znamená změněno . Písmenům a, d nebo c předcházejí čísla řádků zdrojového souboru, za nimiž následují čísla řádků cílového souboru. Každému řádku, který byl přidán, odebrán nebo upraven, předcházejí lomené závorky .

Ve výchozím nastavení nejsou čísla řádků společná pro zdrojové a cílové soubory zadána. Přesunuté řádky jsou zobrazeny jako přidané v novém umístění a jako odstraněné z předchozího umístění. [jeden]

Možnosti

Většina implementací rozdílů zůstala od roku 1975 navenek nezměněna. Úpravy zahrnují vylepšení hlavního algoritmu, přidání nových příkazových kláves, nové výstupní formáty. Základní algoritmus je popsán v An O(ND) Difference Algorithm and its Variations od Eugena W. Myerse [2] a A File Comparison Program od Webba Millera a Myerse [3] . Algoritmus byl nezávisle objeven a popsán v Algorithms for Approximate String Matching od E. Ukkonena [4] . První verze programu diff byly navrženy tak, aby porovnávaly řádky textových souborů pomocí znaku nového řádku jako oddělovače řádků. V 80. letech 20. století vedla podpora binárních souborů ke změnám ve způsobu fungování a implementace programu.

Upravit skript

Editační skript lze generovat moderními verzemi diff s volbou -e . Výsledek pro náš příklad bude vypadat takto:

24a Tento odstavec obsahuje důležité doplňky pro tento dokument. . 17c musí být . 8,14c množství informací. . 0a Toto je důležitá poznámka! Proto by mělo nacházet se na začátku tohoto dokument! .

Abychom mohli výsledný skript použít k převodu původního souboru do nového stavu souboru , musíme na konec skriptu přidat dva řádky: jeden obsahuje příkaz w (write), druhý - q (quit). Například tak . Zde jsme pojmenovali soubor rozdílů mydiff . Transformace proběhne, když zadáme příkaz . printf "w\nq\n" >> mydiffed -s original < mydiff

Kontextový formát

BSD verze 2.8 (vydaná v červenci 1981) zavedla kontextový formát ( -c ) a schopnost rekurzivně procházet strom adresářů souborového systému ( -r ).

V kontextu formátu jsou změněné řádky zobrazeny spolu s neovlivněnými řádky před a za změněným fragmentem. Vložení libovolného počtu neovlivněných řádků poskytuje kontext pro opravu. Kontext , který se skládá z neovlivněných řádků, slouží jako reference pro určení umístění fragmentu, který se upravuje v cílovém souboru, i když se čísla řádků upravených řádků ve zdrojovém a cílovém souboru neshodují. Kontextový formát je pro lidi čitelnější a spolehlivější při aplikaci záplaty a výstup je brán jako vstup do programu záplaty .

Počet neovlivněných řádků před a za upraveným fragmentem může být nastaven uživatelem a může být dokonce nulový, ale obvykle je výchozí hodnota tři řádky. Pokud se kontext neovlivněných čar ve fragmentu překrývá se sousedním fragmentem, pak diff zabrání kopírování neovlivněných čar a sloučí sousední fragmenty do jednoho.

Výstup původního nového příkazu diff -c je:

*** /cesta/k/původní ''časové razítko'' --- /cesta/k/nové ''časové razítko'' *************** *** 1.3 **** --- 1.9 ---- + Toto je důležitá poznámka! + Měl by být + umístěn + na začátku tohoto + dokumentu! + Tato část dokumentu zůstal nezměněn od verze k verzi. Pokud *************** *** 5,20 **** by se nemělo zobrazovat. Jinak to nepomáhá závěr optimální ! vyrobený objem ! Změny. ! ! Tento odstavec obsahuje ! zastaralý text. ! Bude odstraněn ! již brzy. Tento dokument ! musí být Kontrola pravopisu. Na druhou stranu chyba jedním slovem - ne konec světa. --- 11:20 ---- by se nemělo zobrazovat. Jinak to nepomáhá závěr optimální ! množství informací. Tento dokument ! musí být Kontrola pravopisu. Na druhou stranu chyba jedním slovem - ne konec světa. *************** *** 22.24 **** --- 22.28 ---- nevyžaduje změny. Nový text může přidat na konec dokumentu. ++ Tento odstavec obsahuje důležité doplňky + pro tento dokument.

Univerzální formát

Univerzální formát (nebo unidiff ) zahrnuje technická vylepšení kontextového formátu, ale vykresluje rozdíl mezi starým a novým textem stručněji. Univerzální formát se obvykle vyvolává pomocí volby příkazového řádku " -u " . Tento výstup se často používá jako záplata pro programy. Mnoho projektů výslovně požaduje, aby jim byly „rozdíly“ zasílány v obecném formátu, čímž se obecný formát stává nejběžnější výměnou mezi vývojáři softwaru.

Univerzální kontextové rozdíly byly poprvé vyvinuty Waynem Davisonem v srpnu 1990 ( unidiff se objevuje v kapitole 14 comp.sources.misc). Stallman přidal podporu univerzálního formátu do nástroje diff projektu GNU o měsíc později a tato funkce debutovala v GNU diff 1.15, vydaném v lednu 1991. GNU diff od té doby zobecnil kontextový formát, aby umožnil libovolné formátování diffů.

Obecný formátový soubor začíná stejnými dvěma řádky jako kontextový formát, kromě toho, že původní soubor začíná " --- " a nový soubor začíná " +++ ". Za nimi následuje jeden nebo více změněných úryvků , které obsahují změny v souborech po řádcích. Řádky beze změn začínají mezerou, přidané řádky začínají znaménkem plus, smazané řádky začínají znaménkem mínus.

Fragment začíná informací o rozsahu a bezprostředně po něm následují přidané řádky, odstraněné řádky a libovolný počet kontextových řádků. Informace o rozsahu jsou obklopeny dvojitými znaky @ a zřetězeny na jeden řádek, na rozdíl od dvou řádků v ( kontextový formát ). Informace o rozsahu mají následující formát:

@@ -l,s +l,s @@ volitelný nadpis sekce

Informace o rozsahu se skládají ze dvou částí. Část pro původní soubor začíná mínusem a část pro nový soubor začíná plusem. Každá část je ve formátu l, s , kde l  je číslo řádku, kterým začínáme, a s  je počet řádků, které byly změněny v aktuálním fragmentu pro každý ze souborů (tj. v prvním případě se jedná o součet výstupních řádků začínajících mezerou a mínusem, ve druhém - řádků začínajících mezerou a plus). V mnoha verzích GNU diff mohou být čárky a koncové s v každém rozsahu vynechány. V tomto případě je s výchozí hodnotou 1. Všimněte si, že jediná užitečná hodnota pro l samotné  je číslo řádku prvního rozsahu, ostatní hodnoty lze vypočítat z rozdílu.

Fragment rozsahu pro původní soubor musí být součtem veškerého kontextu a odstraněných (včetně upravených) řádků fragmentu. Fragment rozsahu pro nový soubor musí zahrnovat součet všech kontextů a přidaných (včetně upravených) řádků fragmentu.

Fragmentu rozsahu může předcházet záhlaví sekce nebo funkce, jejíž je fragment součástí. To je obvykle užitečné pro čtení samotného úryvku. Při vytváření rozdílu pomocí GNU je hlavička rozdílu určena regulárním výrazem [5] .

Pokud byl řádek změněn, je zobrazen jako odstraněný i přidaný. Protože odstraněné a přidané čáry jsou v sousedních fragmentech, jsou tyto čáry zobrazeny vedle sebe [6] . Například:

- zkontrolujte tento dokument. Na + zkontrolujte tento dokument. Na

Příkaz diff -u original new vytvoří následující výstup:

--- /path/to/original ''timestamp'' +++ /path/to/new ''timestamp'' @@ -1.3 +1.9 @@ +Toto je důležitá poznámka! +Proto by se měl +nacházet na +začátku tohoto +dokumentu! + Tato část dokumentu zůstal nezměněn od verze k verzi. Pokud @@ -5,16 +11,10 @@ by se nemělo zobrazovat. Jinak to nepomáhá závěr optimální - objem provedených změn. - -Tento odstavec obsahuje zastaralý text. -Bude odstraněn -v blízké budoucnosti. + množství informací. Tento dokument - musí být provedeno + musí být provedeno Kontrola pravopisu. Na druhou stranu chyba jedním slovem - ne konec světa. @@ -22,3 +22,7 @@ nevyžaduje změny. Nový text může přidat na konec dokumentu. ++ Tento odstavec obsahuje +důležité doplňky +pro tento dokument.

Všimněte si, že tabulátory se používají ke správnému oddělení názvů souborů od časových razítek. To je na obrazovce neviditelné a při kopírování/vkládání z konzole se může ztratit.

Existuje několik úprav a rozšíření formátů rozdílů, které různé programy používají a rozumí jim. Například některé systémy pro správu verzí , jako je Subversion , specifikují kromě časového razítka v záhlaví rozdílu také číslo verze, "pracovní kopii" nebo jakýkoli jiný komentář.

Některé programy umožňují vytvářet rozdíly pro několik různých souborů a sloučit je do jednoho pomocí záhlaví pro každý změněný soubor, které může vypadat nějak takto:

Index: cesta/k/souboru.cpp

Zvláštní druh souborů, které nekončí novým řádkem, není podporován. Ani obslužný program unidiff, ani standard POSIX diff neurčují, jak se s takovými soubory zachází (ve skutečnosti soubory tohoto typu nejsou "textové" v definici POSIX [7] ).

Opravný program neví nic o implementaci speciálního výstupu příkazu diff.

Viz také

Poznámky

  1. David MacKenzie, Paul Eggert a Richard Stallman. Porovnání a sloučení souborů pomocí GNU Diff a  Patch . — 1997.
  2. E. Myers. O(ND ) rozdílový algoritmus a jeho variace   // Algorithmica : deník. - 1986. - Sv. 1 , ne. 2 . - str. 251-266 .
  3. Webb Miller a Eugene W. Myers. Program pro porovnávání souborů // Software – praxe a zkušenosti. - 1985. - T. 15 , č. 11 . - S. 1025-1040 .
  4. E. Ukkonen. Algoritmy  pro přibližné  porovnávání řetězců // Informace a výpočty : deník. - 1985. - Sv. 64 . - str. 100-118 .
  5. 2.2.3 Zobrazení rozdílů v sekcích Archivováno 26. května 2013 na Wayback Machine , příručka GNU diffutils 
  6. Unified Diff Format Archived 5. dubna 2013 na Wayback Machine od Guida van Rossuma , 14. června  2006
  7. http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_205 Archivováno 29. dubna 2013 v sekci Wayback Machine Section 3.205 

Odkazy