Přejít k obsahu

Rozdíl

Pitmaster počítá diffy v jednotném formátu git. Nástroj pro výpočet diffů podporuje více algoritmů, formátování jednotného diffu, detekci binárních souborů a rekurzivní porovnávání na úrovni stromu.

U upraveného textového souboru s režimem 100644 vytváří format() stejné bajty jako git diff. Ostatní případy jsou nyní formátovány odlišně (#3):

  • Nové a smazané soubory nemají řádek new file mode / deleted file mode, řádek index ani /dev/null: obě strany jsou označeny jako a/<path> a b/<path> a rozsah bloku změn prázdné strany se zapisuje jako -1,0 nebo +1,0, kde git zapisuje -0,0 nebo +0,0.
  • Řádek index vždy končí znakem 100644, bez ohledu na režim souboru.
  • Změny pouze režimu (například chmod +x) nevytvářejí žádný výsledek.
  • Binární soubory vypisují Binary files differ bez řádku index, zatímco git vypisuje Binary files a/<path> and b/<path> differ.
  • Přejmenování se zobrazují jako jedna položka diff --git a/<old> b/<new> s diffem obsahu, bez řádků similarity index, rename from ani rename to.

Operace s rozdíly

Nepřipravené změny (pracovní strom oproti indexu)

PHP
$diffs = $repo->diff();

foreach ($diffs as $diff) {
    echo $diff->format();
}

Porovnává každý soubor v indexu s jeho aktuálním stavem v pracovním stromu. Zjišťuje úpravy, odstranění a binární soubory.

Připravené změny (index oproti HEAD)

PHP
$diffs = $repo->diffStaged();

foreach ($diffs as $diff) {
    echo $diff->format();
}

Porovnává aktuální index se stromem commitu HEAD. Zobrazuje, co bude zahrnuto do příštího commitu. Odstraněné a přidané soubory s podobným obsahem se zobrazí jako jedna přejmenovaná položka. Před prvním commitem HEAD neexistuje a výsledek je prázdný (#5).

Párování přejmenovaných souborů v současnosti odpovídá také nesouvisejícím jednořádkovým souborům, protože koncový prázdný řádek se započítává jako společný obsah (#4).

Rozdíl mezi stromy

PHP
$a = $repo->readObject($repo->resolve('HEAD~1')->hex)->tree;
$b = $repo->head()->tree;
$diffs = $repo->diffTree($a, $b);

Rekurzivně porovnává dva stromy. Předávejte ID stromů: ID commitů se na jejich stromy nepřevádějí a vrátí prázdný výsledek. Stejný modul TreeDiff využívají diffStaged(), show() a logPath().

Filtrování podle cesty

PHP
$diffs = $repo->diff('src/specific-file.php');

Specifikace cesty je přesná cesta k jednomu souboru. diffStaged() přijímá stejný argument, ale momentálně ho ignoruje, takže vždy vrací všechny připravené soubory (#5).

Výběr algoritmu

PHP
$diffs = $repo->diff(null, 'patience');
$diffs = $repo->diffStaged(null, 'histogram');
$diffs = $repo->diffTree($a, $b, 'minimal');

Platné názvy jsou myers (výchozí), patience, histogram a minimal. Jakýkoli jiný název vyvolá InvalidArgumentException.

Struktura DiffResult

Každý DiffResult představuje rozdíl pro jeden soubor.

PHP
use Pitmaster\Diff\DiffResult;

foreach ($diffs as $diff) {
    echo $diff->oldPath;    // Path in the old tree
    echo $diff->newPath;    // Path in the new tree
    echo $diff->binary;     // true for binary files
    echo $diff->oldHash;    // Hex hash of the old blob (null for added files)
    echo $diff->newHash;    // Hex hash of the new blob (null for deleted files)

    foreach ($diff->hunks as $hunk) {
        echo $hunk->header();  // @@ -1,5 +1,7 @@
        foreach ($hunk->lines as $line) {
            echo $line . "\n"; // ' context', '+added', '-removed'
        }
    }
}

Formátovaný výstup

PHP
echo $diff->format();

Vytváří výstup jednotného rozdílu. U upraveného textového souboru odpovídá git diff:

Kód
diff --git a/src/File.php b/src/File.php
index abc1234..def5678 100644
--- a/src/File.php
+++ b/src/File.php
@@ -10,6 +10,8 @@ class File
     private string $name;

+    private int $count;
+
     public function __construct()
     {

Kontrola změn

PHP
if ($diff->hasChanges()) {
    // File was modified (or is binary with changes)
}

Struktura hunku

Každý Hunk představuje souvislou oblast změn s kontextovými řádky.

PHP
use Pitmaster\Diff\Hunk;

$hunk->oldStart;   // Starting line in old file
$hunk->oldCount;   // Number of lines from old file
$hunk->newStart;   // Starting line in new file
$hunk->newCount;   // Number of lines in new file
$hunk->lines;      // Array of diff lines (prefixed with ' ', '+', or '-')
$hunk->header();   // "@@ -10,6 +10,8 @@"

Algoritmy rozdílů

Pitmaster implementuje čtyři algoritmy pro výpočet rozdílů. Výchozí je Myersův algoritmus.

Myersův algoritmus

Standardní algoritmus O(ND), stejný jako výchozí algoritmus git. Vytváří minimální skripty úprav.

PHP
use Pitmaster\Diff\MyersDiff;

$hunks = MyersDiff::diff($oldContent, $newContent);

Metoda diff() přijímá dva řetězce a vrací pole objektů Hunk. Rozdělí vstup podle nových řádků, vypočítá nejkratší posloupnost úprav a seskupí změny do bloků se 3 řádky kontextu (podle výchozího nastavení git).

Diff metodou trpělivosti

Lepší strukturální diffy kódu. Nejprve porovná jedinečné řádky a pak doplní obsah mezi nimi.

PHP
use Pitmaster\Diff\PatienceDiff;

$hunks = PatienceDiff::diff($oldContent, $newContent);

Histogramový diff

Varianta diffu metodou trpělivosti, která lépe zvládá opakující se řádky. Používají ji JGit a Eclipse.

PHP
use Pitmaster\Diff\HistogramDiff;

$hunks = HistogramDiff::diff($oldContent, $newContent);

Minimální diff

Vytvoří co nejmenší diff (s nejmenším počtem změněných řádků), za cenu delšího výpočtu.

PHP
use Pitmaster\Diff\MinimalDiff;

$hunks = MinimalDiff::diff($oldContent, $newContent);

Detekce binárních souborů

Pitmaster považuje obsah za binární, pokud se v jeho prvních 8192 bajtech nachází bajt NUL (git kontroluje prvních 8000).

PHP
if (MyersDiff::isBinary($content)) {
    // Binary file, skip line-level diff
}

Binární soubory vytvoří DiffResult s $binary = true a prázdným polem $hunks. Formátovaný výstup:

Kód
diff --git a/image.png b/image.png
Binary files differ

Barevný výstup

CLI pro výstup do terminálu používá ColorDiff a ANSI barvy.

PHP
use Pitmaster\Diff\ColorDiff;

$colorized = ColorDiff::colorize($diff->format());
echo $colorized;
  • Přidané řádky (+) se zobrazují zeleně
  • Odebrané řádky (-) se zobrazují červeně
  • Záhlaví bloků (@@) se zobrazují azurově
  • Záhlaví souborů (diff --git, index, ---, +++) se zobrazují tučně

pitmaster diff vždy obarví výstup, i když je přesměrován. pitmaster show obarví výstup pouze tehdy, když je stdout terminál.

Diff stromu (interní)

Třída TreeDiff rekurzivně porovnává dva objekty stromu a pro každý změněný soubor vytváří DiffResult.

PHP
use Pitmaster\Diff\TreeDiff;

$treeDiff = new TreeDiff($repo->objectDatabase());
$diffs = $treeDiff->diff($oldTreeId, $newTreeId);

Diff stromu zpracovává:

  • Přidané soubory (jsou pouze v novém stromu)
  • Smazané soubory (jsou pouze ve starém stromu)
  • Upravené soubory (stejná cesta, jiný hash blobu)
  • Rekurzivní porovnání podadresářů
  • Párování přejmenovaných souborů mezi smazanými a přidanými (shoda celého hashe nebo alespoň 50 % společných řádků)

Položky se stejným hashem se přeskočí, takže samotná změna režimu nevytvoří žádný výsledek.

Diff slov

Pro změny jednotlivých slov uvnitř řádků.

PHP
use Pitmaster\Diff\WordDiff;

$result = WordDiff::diff('the quick fox', 'the slow fox');
// 'the [-quick-]{+slow+} fox'