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".
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.
Operace diff je založena na nalezení nejdelší společné podsekvence ( problém LCS) . Například existují dvě sekvence prvků:
abcdfghjqz abcdefgijkrxyza 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
abcdfgjzPo získání největší společné sekvence zbývá jen malý krok, než získáte výstup podobný rozdílu:
ehikqrxy + - + + - + + +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]
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.
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
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 (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 sekceInformace 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. NaPří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.cppZvláš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.
Systémy řízení verzí ( kategorie ) | |
---|---|
Pouze místní | |
Klient-server | |
Distribuováno | |