
# Rozdiely

Pitmaster vypočítava rozdiely vo formáte unified git. Nástroj na výpočet rozdielov podporuje viacero algoritmov, formátovanie unified diff, detekciu binárnych súborov a rekurzívne porovnávanie na úrovni stromov.

Pri upravenom textovom súbore s režimom `100644` vytvára `format()` rovnaké bajty ako `git diff`. Ostatné prípady sa momentálne formátujú odlišne ([#3](https://github.com/inline0/pitmaster/issues/3)):

- Nové a odstránené súbory nemajú riadok `new file mode` / `deleted file mode`, riadok `index` ani `/dev/null`: obe strany sú označené ako `a/<path>` a `b/<path>` a rozsah bloku prázdnej strany sa zapisuje ako `-1,0` alebo `+1,0`, zatiaľ čo git zapisuje `-0,0` alebo `+0,0`.
- Riadok `index` vždy končí na `100644` bez ohľadu na režim súboru.
- Zmeny iba režimu (napríklad `chmod +x`) nevytvárajú žiadny výsledok.
- Binárne súbory vypíšu `Binary files differ` bez riadku `index`, zatiaľ čo git vypíše `Binary files a/<path> and b/<path> differ`.
- Premenovania sa zobrazujú ako jedna položka `diff --git a/<old> b/<new>` s rozdielom v obsahu, bez riadkov `similarity index`, `rename from` ani `rename to`.

## Operácie s rozdielmi

### Nepripravené zmeny (pracovný strom vs. index)

```php
$diffs = $repo->diff();

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

Porovná každý súbor v indexe s jeho aktuálnym stavom v pracovnom strome. Zisťuje úpravy, odstránenia a binárne súbory.

### Pripravené zmeny (index vs. HEAD)

```php
$diffs = $repo->diffStaged();

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

Porovnáva aktuálny index so stromom commitu HEAD. Zobrazuje, čo sa zahrnie do nasledujúceho commitu. Odstránené a pridané súbory s podobným obsahom sa vykážu ako jedna premenovaná položka. Pred prvým commitom HEAD neexistuje a výsledok je prázdny ([#5](https://github.com/inline0/pitmaster/issues/5)).

Párovanie premenovaní momentálne rozpozná aj nesúvisiace jednoradkové súbory, pretože koncový prázdny riadok sa počíta ako zdieľaný obsah ([#4](https://github.com/inline0/pitmaster/issues/4)).

### Rozdiel medzi stromami

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

Rekurzívne porovnáva dva stromy. Zadajte ID stromov: ID commitov sa neprevádzajú na ich stromy a výsledkom je prázdny výstup. Rovnaký nástroj `TreeDiff` používa aj `diffStaged()`, `show()` a `logPath()`.

### Filtrovanie podľa cesty

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

Špecifikácia cesty predstavuje presnú cestu k súboru. `diffStaged()` prijíma rovnaký argument, ale momentálne ho ignoruje, takže vždy vráti všetky pripravené súbory ([#5](https://github.com/inline0/pitmaster/issues/5)).

### Výber algoritmu

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

Platné názvy sú `myers` (predvolený), `patience`, `histogram` a `minimal`. Každý iný názov vyvolá `InvalidArgumentException`.

## Štruktúra DiffResult

Každý `DiffResult` predstavuje rozdiely pre jeden súbor.

```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();
```

Vytvorí výstup unified diff. Pri upravenom textovom súbore zodpovedá `git diff`:

```
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 zmien

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

## Štruktúra bloku

Každý `Hunk` predstavuje súvislú oblasť zmien s kontextovými riadkami.

```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 na výpočet rozdielov

Pitmaster implementuje štyri algoritmy na výpočet rozdielov. Predvolený je Myers.

### Rozdiely Myers

Štandardný algoritmus O(ND), rovnaký ako predvolený algoritmus v git. Vytvára minimálne skripty úprav.

```php
use Pitmaster\Diff\MyersDiff;

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

Metóda `diff()` prijíma dva reťazce a vracia pole objektov `Hunk`. Rozdelí vstup podľa nových riadkov, vypočíta najkratší skript úprav a zoskupí zmeny do blokov s 3 kontextovými riadkami (zhoduje sa s predvoleným nastavením v git).

### Rozdiely Patience

Vytvára štrukturálne prehľadnejšie rozdiely v kóde. Najprv spáruje jedinečné riadky a potom doplní zvyšok medzi nimi.

```php
use Pitmaster\Diff\PatienceDiff;

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

### Rozdiely Histogram

Variant rozdielov Patience, ktorý lepšie spracúva opakované riadky. Používajú ho JGit a Eclipse.

```php
use Pitmaster\Diff\HistogramDiff;

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

### Minimálne rozdiely

Vytvára čo najmenšie rozdiely (s najmenším počtom zmenených riadkov) za cenu dlhšieho výpočtu.

```php
use Pitmaster\Diff\MinimalDiff;

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

## Rozpoznávanie binárnych súborov

Pitmaster považuje obsah za binárny, ak obsahuje bajt NUL v prvých 8192 bajtoch (git kontroluje prvých 8000).

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

Binárne súbory vytvoria `DiffResult` s `$binary = true` a prázdnym poľom `$hunks`. Formátovaný výstup:

```
diff --git a/image.png b/image.png
Binary files differ
```

## Farebný výstup

CLI používa `ColorDiff` na výstup v termináli s farbami ANSI.

```php
use Pitmaster\Diff\ColorDiff;

$colorized = ColorDiff::colorize($diff->format());
echo $colorized;
```

- Pridané riadky (`+`) sa zobrazujú zelenou farbou
- Odstránené riadky (`-`) sa zobrazujú červenou farbou
- Hlavičky blokov (`@@`) sa zobrazujú azúrovou farbou
- Hlavičky súborov (`diff --git`, `index`, `---`, `+++`) sa zobrazujú tučným písmom

`pitmaster diff` vždy pridáva farby, aj keď je jeho výstup presmerovaný do rúry. `pitmaster show` pridáva farby, iba keď je stdout terminál.

## Rozdiely stromov (interné)

Trieda `TreeDiff` rekurzívne porovnáva dva objekty stromu a vytvára `DiffResult` pre každý zmenený súbor.

```php
use Pitmaster\Diff\TreeDiff;

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

Rozdiely stromov spracúvajú:
- Pridané súbory (iba v novom strome)
- Odstránené súbory (iba v starom strome)
- Upravené súbory (rovnaká cesta, iný hash objektu blob)
- Rekurzívne porovnávanie podadresárov
- Párovanie premenovaných súborov medzi odstránenými a pridanými súbormi (presná zhoda hashov alebo aspoň 50 % spoločných riadkov)

Položky s nezmeneným hashom sa preskočia, takže samotná zmena režimu nevytvorí výsledok.

## Rozdiely slov

Na zmeny jednotlivých slov priamo v riadkoch.

```php
use Pitmaster\Diff\WordDiff;

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