
# Erinevused

Pitmaster arvutab erinevused git-i ühtlustatud vormingus. Võrdlusmootor toetab mitut algoritmi, ühtlustatud erinevuste vormingut, binaarfailide tuvastamist ja rekursiivset puude võrdlust.

Muudetud tekstifaili puhul, mille režiim on `100644`, toodab `format()` samad baidid nagu `git diff`. Muudel juhtudel vormindatakse tulemus praegu teisiti ([#3](https://github.com/inline0/pitmaster/issues/3)):

- Uutel ja kustutatud failidel puuduvad rida `new file mode` / `deleted file mode`, rida `index` ja `/dev/null`: mõlemad pooled on tähistatud kui `a/<path>` ja `b/<path>` ning tühja poole hunk'i vahemik esitatakse kujul `-1,0` või `+1,0`, seal kus git kirjutab `-0,0` või `+0,0`.
- Rida `index` lõpeb alati märgiga `100644`, olenemata failirežiimist.
- Ainult režiimi muudatused (näiteks `chmod +x`) tulemust ei anna.
- Binaarfailide puhul väljastatakse `Binary files differ` ilma reata `index`; git väljastab `Binary files a/<path> and b/<path> differ`.
- Ümbernimetamised kuvatakse ühe `diff --git a/<old> b/<new>` kirjena koos sisu erinevustega, ilma ridadeta `similarity index`, `rename from` või `rename to`.

## Erinevuste toimingud

### Lavastamata muudatused (tööpuu vs indeks)

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

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

Võrdleb indeksi iga faili selle praeguse olekuga tööpuus. Tuvastab muudatused, kustutamised ja binaarfailid.

### Lavastatud muudatused (indeks vs HEAD)

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

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

Võrdleb praegust indeksit HEAD-i sissekande puuga. Näitab, mis lisatakse järgmisse sissekandesse. Sarnase sisuga kustutatud ja lisatud failid esitatakse ühe ümbernimetatud kirjena. Enne esimest sissekannet HEAD puudub ja tulemus on tühi ([#5](https://github.com/inline0/pitmaster/issues/5)).

Ümbernimetamiste paaride leidmine seostab praegu ka omavahel mitteseotud üherealisi faile, sest lõpus olev tühi rida loetakse ühiseks sisuks ([#4](https://github.com/inline0/pitmaster/issues/4)).

### Puudevahelised erinevused

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

Võrdleb rekursiivselt kahte puud. Edastage puude ID-d: sissekannete ID-sid nende puudeks ei lahutata ja need annavad tühja tulemuse. Sama `TreeDiff` mootor on aluseks toimingutele `diffStaged()`, `show()` ja `logPath()`.

### Tee järgi filtreerimine

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

Teemäärang on ühe täpse failitee jaoks. `diffStaged()` aktsepteerib sama argumenti, kuid eirab seda praegu, seega tagastab alati kõik lavastatud failid ([#5](https://github.com/inline0/pitmaster/issues/5)).

### Algoritmi valimine

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

Kehtivad nimed on `myers` (vaikimisi), `patience`, `histogram` ja `minimal`. Mis tahes muu nimi põhjustab vea `InvalidArgumentException`.

## DiffResulti struktuur

Iga `DiffResult` tähistab ühe faili erinevusi.

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

### Vormindatud väljund

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

Loob ühtlustatud erinevuste väljundi. Muudetud tekstifaili korral vastab see `git diff`-le:

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

### Muudatuste kontrollimine

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

## Hunk'i struktuur

Iga `Hunk` tähistab muudatuste külgnevat lõiku koos kontekstiridadega.

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

## Erinevuste algoritmid

Pitmaster rakendab nelja erinevuste algoritmi. Vaikimisi kasutatakse Myersit.

### Myersi erinevuste algoritm

Standardne O(ND) algoritm, sama mis git-i vaikealgoritm. Loob minimaalsed muudatuste skriptid.

```php
use Pitmaster\Diff\MyersDiff;

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

`diff()` meetod võtab kaks stringi ja tagastab hulga `Hunk` objekte. See jagab sisendi reavahetuste järgi, arvutab lühima muudatuste skripti ja koondab muudatused hunk'ideks, milles on 3 kontekstirida (git-i vaikeväärtus).

### Patience'i erinevuste algoritm

Parem struktuursete erinevuste tuvastamine koodi puhul. Sobitab esmalt kordumatud read, seejärel leiab vasted nende vahele jäävatele ridadele.

```php
use Pitmaster\Diff\PatienceDiff;

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

### Histogrammi erinevuste algoritm

Patience'i erinevuste algoritmi variant, mis käsitleb korduvaid ridu paremini. Seda kasutavad JGit ja Eclipse.

```php
use Pitmaster\Diff\HistogramDiff;

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

### Minimaalsete erinevuste algoritm

Loob võimalikult väikese erinevuste väljundi (vähim arv muudetud ridu), kuid nõuab rohkem arvutustööd.

```php
use Pitmaster\Diff\MinimalDiff;

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

## Binaarfailide tuvastamine

Pitmaster käsitleb sisu binaarsena, kui selle esimese 8192 baidi seas leidub NUL-bait (git kontrollib esimest 8000 baiti).

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

Binaarfailide puhul luuakse `DiffResult`, millel on `$binary = true` ja tühi massiiv `$hunks`. Vormindatud väljund on järgmine:

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

## Värviline väljund

CLI kasutab terminaliväljundi värvimiseks `ColorDiff`.

```php
use Pitmaster\Diff\ColorDiff;

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

- Lisatud read (`+`) kuvatakse rohelisena
- Eemaldatud read (`-`) kuvatakse punasena
- Hunk'i päised (`@@`) kuvatakse tsüaanina
- Failipäised (`diff --git`, `index`, `---`, `+++`) kuvatakse paksus kirjas

`pitmaster diff` värvib väljundi alati, ka torusse suunamisel. `pitmaster show` värvib ainult siis, kui standardväljund on terminal.

## Puude võrdlemine (sisemine)

Klass `TreeDiff` võrdleb rekursiivselt kahte puuobjekti ja loob iga muudetud faili kohta objekti `DiffResult`.

```php
use Pitmaster\Diff\TreeDiff;

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

Puude võrdlemine käsitleb järgmist:
- Lisatud failid (esinevad ainult uues puus)
- Kustutatud failid (esinevad ainult vanas puus)
- Muudetud failid (sama tee, erinev bloobi räsi)
- Alamkataloogide rekursiivne võrdlemine
- Ümbernimetamise sobitamine kustutatud ja lisatud failide vahel (täpne räsivaste või vähemalt 50% ühistest ridadest)

Muutumatu räsiga kirjed jäetakse vahele, seega ainult režiimi muutmine tulemust ei anna.

## Sõnade võrdlus

Ridade sees toimuvate tekstisiseste sõnataseme muudatuste jaoks.

```php
use Pitmaster\Diff\WordDiff;

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