
# Razlike

Pitmaster izračuna razlike v poenoteni obliki git. Pogon za izračun razlik podpira več algoritmov, oblikovanje poenotenih razlik, zaznavanje binarnih datotek in rekurzivno primerjavo na ravni dreves.

Za spremenjeno besedilno datoteko z načinom `100644` ustvari `format()` enake bajte kot `git diff`. Drugi primeri so trenutno oblikovani drugače ([#3](https://github.com/inline0/pitmaster/issues/3)):

- Nove in izbrisane datoteke nimajo vrstice `new file mode` / `deleted file mode`, vrstice `index` ali `/dev/null`: obe strani sta označeni kot `a/<path>` in `b/<path>`, obseg bloka prazne strani pa je zapisan kot `-1,0` ali `+1,0`, medtem ko git zapiše `-0,0` ali `+0,0`.
- Vrstica `index` se vedno konča z `100644`, ne glede na način datoteke.
- Spremembe samo načina (na primer `chmod +x`) ne ustvarijo rezultata.
- Binarne datoteke izpišejo `Binary files differ` brez vrstice `index`, medtem ko git izpiše `Binary files a/<path> and b/<path> differ`.
- Preimenovanja so prikazana kot en vnos `diff --git a/<old> b/<new>` z razliko v vsebini, brez vrstic `similarity index`, `rename from` ali `rename to`.

## Operacije z razlikami

### Nepripravljene spremembe (delovno drevo proti indeksu)

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

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

Primerja vsako datoteko v indeksu z njenim trenutnim stanjem v delovnem drevesu. Zazna spremembe, izbrise in binarne datoteke.

### Pripravljene spremembe (indeks proti HEAD)

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

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

Primerja trenutni indeks z drevesom potrditve HEAD. Prikaže, kaj bo vključeno v naslednjo potrditev. Izbrisane in dodane datoteke s podobno vsebino se prikažejo kot en preimenovani vnos. Pred prvo potrditvijo HEAD ne obstaja, zato je rezultat prazen ([#5](https://github.com/inline0/pitmaster/issues/5)).

Povezovanje preimenovanj trenutno poveže tudi nepovezane enovrstične datoteke, saj se zaključna prazna vrstica šteje kot skupna vsebina ([#4](https://github.com/inline0/pitmaster/issues/4)).

### Primerjava dreves

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

Rekurzivno primerja dve drevesi. Podajte ID-je dreves: ID-ji potrditev se ne pretvorijo v njihova drevesa, zato je rezultat prazen. Isti pogon `TreeDiff` poganja `diffStaged()`, `show()` in `logPath()`.

### Filtriranje po poti

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

Specifikacija poti je ena natančna pot do datoteke. `diffStaged()` sprejme isti argument, vendar ga trenutno prezre, zato vedno vrne vse pripravljene datoteke ([#5](https://github.com/inline0/pitmaster/issues/5)).

### Izbira algoritma

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

Veljavna imena so `myers` (privzeto), `patience`, `histogram` in `minimal`. Vsako drugo ime sproži `InvalidArgumentException`.

## Struktura DiffResult

Vsak `DiffResult` predstavlja razliko za eno datoteko.

```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'
        }
    }
}
```

### Oblikovani izpis

```php
echo $diff->format();
```

Ustvari poenoten izpis razlik. Pri spremenjeni besedilni datoteki se ujema z `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()
     {
```

### Preverjanje sprememb

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

## Struktura bloka

Vsak `Hunk` predstavlja neprekinjen odsek sprememb z vrsticami konteksta.

```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 @@"
```

## Algoritmi za izračun razlik

Pitmaster izvaja štiri algoritme za izračun razlik. Privzeti je Myers.

### Razlike po Myersu

Standardni algoritem O(ND), enak privzetemu algoritmu v git. Ustvari minimalne zapise urejanja.

```php
use Pitmaster\Diff\MyersDiff;

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

Metoda `diff()` sprejme dva niza in vrne polje objektov `Hunk`. Vhod razdeli po novih vrsticah, izračuna najkrajši zapis urejanja in združi spremembe v bloke s 3 vrsticami konteksta (kot pri privzeti nastavitvi v git).

### Razlike po metodi patience

Ustvari boljše strukturne razlike za kodo. Najprej poveže enolične vrstice, nato zapolni prostor med njimi.

```php
use Pitmaster\Diff\PatienceDiff;

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

### Histogram razlik

Različica metode patience, ki bolje obravnava ponovljene vrstice. Uporabljata jo JGit in Eclipse.

```php
use Pitmaster\Diff\HistogramDiff;

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

### Minimalne razlike

Ustvari najmanjšo možno razliko (z najmanj spremenjenimi vrsticami), a zahteva več računanja.

```php
use Pitmaster\Diff\MinimalDiff;

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

## Zaznavanje binarnih datotek

Pitmaster obravnava vsebino kot binarno, če je v prvih 8192 bajtih bajt NUL (git preveri prvih 8000).

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

Binarne datoteke ustvarijo `DiffResult` z `$binary = true` in praznim poljem `$hunks`. Oblikovani izpis je:

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

## Barvni izpis

CLI za izpis v terminal uporablja `ColorDiff` z barvami ANSI.

```php
use Pitmaster\Diff\ColorDiff;

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

- Dodane vrstice (`+`) so prikazane zeleno
- Odstranjene vrstice (`-`) so prikazane rdeče
- Glave blokov (`@@`) so prikazane cian
- Glave datotek (`diff --git`, `index`, `---`, `+++`) so prikazane krepko

`pitmaster diff` vedno uporablja barve, tudi ko je njegov izhod preusmerjen. `pitmaster show` uporablja barve samo, kadar je stdout terminal.

## Primerjava dreves (notranje)

Razred `TreeDiff` rekurzivno primerja dva drevesna objekta in ustvari `DiffResult` za vsako spremenjeno datoteko.

```php
use Pitmaster\Diff\TreeDiff;

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

Primerjava dreves obravnava:
- Dodane datoteke (prisotne samo v novem drevesu)
- Izbrisane datoteke (prisotne samo v starem drevesu)
- Spremenjene datoteke (ista pot, drugačna zgoščena vrednost vsebine)
- Rekurzivno primerjavo podimenikov
- Povezovanje preimenovanj med izbrisanimi in dodanimi datotekami (natančno ujemanje zgoščene vrednosti ali vsaj 50 % skupnih vrstic)

Vnosi z nespremenjeno zgoščeno vrednostjo so preskočeni, zato sprememba načina sama po sebi ne ustvari rezultata.

## Razlike na ravni besed

Za spremembe posameznih besed znotraj vrstic.

```php
use Pitmaster\Diff\WordDiff;

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