
# Skirtumas

Pitmaster apskaičiuoja git vieninguoju formatu pateikiamus skirtumus. Skirtumų modulis palaiko kelis algoritmus, vieningąjį formatavimą, dvejetainių failų aptikimą ir rekursinį palyginimą medžių lygmeniu.

Pakeistam tekstiniam failui, kurio režimas `100644`, `format()` sukuria tuos pačius baitus kaip `git diff`. Kiti atvejai šiuo metu formatuojami kitaip ([#3](https://github.com/inline0/pitmaster/issues/3)):

- Nauji ir ištrinti failai neturi `new file mode` / `deleted file mode` eilutės, `index` eilutės ir `/dev/null`: abi pusės žymimos `a/<path>` ir `b/<path>`, o tuščios pusės hunk intervalas užrašomas kaip `-1,0` arba `+1,0`, kai git užrašo `-0,0` arba `+0,0`.
- `index` eilutė visada baigiasi `100644`, nepriklausomai nuo failo režimo.
- Vien režimo pakeitimai (pavyzdžiui, `chmod +x`) nesukuria rezultato.
- Dvejetainiai failai pateikia `Binary files differ` be `index` eilutės, o git pateikia `Binary files a/<path> and b/<path> differ`.
- Pervadinimai rodomi kaip vienas `diff --git a/<old> b/<new>` įrašas su turinio skirtumu, be `similarity index`, `rename from` ar `rename to` eilučių.

## Skirtumų operacijos

### Nepatvirtinti pakeitimai (darbinis medis ir indeksas)

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

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

Palygina kiekvieną indekso failą su jo dabartine būsena darbiniame medyje. Aptinka pakeitimus, ištrynimus ir dvejetainius failus.

### Paruošti pakeitimai (indeksas ir HEAD)

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

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

Palygina dabartinį indeksą su HEAD įrašo medžiu. Parodo, kas bus įtraukta į kitą įrašą. Ištrinti ir pridėti failai su panašiu turiniu pateikiami kaip vienas pervadintas įrašas. Prieš pirmąjį įrašą HEAD nėra, todėl rezultatas tuščias ([#5](https://github.com/inline0/pitmaster/issues/5)).

Šiuo metu pervadinimų poravimas taip pat susieja nesusijusius vienos eilutės failus, nes pabaigos tuščia eilutė laikoma bendru turiniu ([#4](https://github.com/inline0/pitmaster/issues/4)).

### Medžių palyginimas

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

Rekursyviai palygina du medžius. Perduokite medžių ID: įrašų ID nepaverčiami jų medžiais, todėl gaunamas tuščias rezultatas. Tą patį `TreeDiff` modulį naudoja `diffStaged()`, `show()` ir `logPath()`.

### Filtruoti pagal kelią

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

Kelio specifikacija yra tikslus failo kelias. `diffStaged()` priima tą patį argumentą, bet šiuo metu jo nepaiso, todėl visada grąžina visus paruoštus failus ([#5](https://github.com/inline0/pitmaster/issues/5)).

### Pasirinkti algoritmą

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

Galiojantys pavadinimai: `myers` (numatytasis), `patience`, `histogram` ir `minimal`. Bet kuris kitas pavadinimas sukelia `InvalidArgumentException`.

## DiffResult struktūra

Kiekvienas `DiffResult` atspindi vieno failo skirtumą.

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

### Suformatuota išvestis

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

Sukuria vieningąją skirtumų išvestį. Pakeistam tekstiniam failui ji atitinka `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()
     {
```

### Tikrinti, ar yra pakeitimų

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

## Hunk struktūra

Kiekvienas `Hunk` atspindi gretimą pakeitimų sritį su konteksto eilutėmis.

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

## Skirtumų algoritmai

Pitmaster įgyvendina keturis skirtumų algoritmus. Numatytasis yra Myers.

### Myers skirtumas

Standartinis O(ND) algoritmas, toks pat kaip numatytasis git algoritmas. Sukuria minimalius redagavimo scenarijus.

```php
use Pitmaster\Diff\MyersDiff;

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

`diff()` metodas priima dvi eilutes ir grąžina `Hunk` objektų masyvą. Įvestį jis suskaido pagal naujas eilutes, apskaičiuoja trumpiausią redagavimo scenarijų ir sugrupuoja pakeitimus į hunk blokus su 3 konteksto eilutėmis (kaip numatyta git).

### Kantrybės skirtumas

Sukuria geresnius struktūrinius kodo skirtumus. Pirmiausia sulygina unikalias eilutes, tada užpildo tarpus tarp jų.

```php
use Pitmaster\Diff\PatienceDiff;

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

### Histogramos skirtumas

Kantrybės skirtumo variantas, geriau apdorojantis pasikartojančias eilutes. Naudoja JGit ir Eclipse.

```php
use Pitmaster\Diff\HistogramDiff;

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

### Minimalus skirtumas

Sukuria mažiausią įmanomą skirtumą (su mažiausiai pakeistų eilučių), tačiau skaičiavimas užtrunka ilgiau.

```php
use Pitmaster\Diff\MinimalDiff;

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

## Dvejetainių failų aptikimas

Pitmaster turinį laiko dvejetainiu, jei tarp pirmųjų 8192 baitų yra NUL baitas (git tikrina pirmuosius 8000).

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

Dvejetainiai failai sukuria `DiffResult` su `$binary = true` ir tuščiu `$hunks` masyvu. Suformatuota išvestis:

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

## Spalvota išvestis

CLI terminalo išvestyje naudoja `ColorDiff` ANSI spalvas.

```php
use Pitmaster\Diff\ColorDiff;

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

- Pridėtos eilutės (`+`) rodomos žaliai
- Pašalintos eilutės (`-`) rodomos raudonai
- Hunk antraštės (`@@`) rodomos žydrai
- Failų antraštės (`diff --git`, `index`, `---`, `+++`) rodomos paryškintai

`pitmaster diff` visada nuspalvina išvestį, net kai ji perduodama per dujotiekį. `pitmaster show` nuspalvina tik tada, kai stdout yra terminalas.

## Medžių skirtumas (vidinis)

`TreeDiff` klasė rekursyviai palygina du medžio objektus ir sukuria po `DiffResult` kiekvienam pakeistam failui.

```php
use Pitmaster\Diff\TreeDiff;

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

Medžių skirtumo apdorojimas:
- Pridėti failai (yra tik naujame medyje)
- Ištrinti failai (yra tik sename medyje)
- Pakeisti failai (tas pats kelias, skiriasi blob maiša)
- Rekursinis poaplankių palyginimas
- Ištrintų ir pridėtų failų poravimas pervadinimams (tiksli maiša arba bent 50% bendrų eilučių)

Įrašai, kurių maiša nepasikeitė, praleidžiami, todėl vien režimo pakeitimas rezultato nesukuria.

## Žodžių skirtumas

Skirta eilučių viduje esantiems žodžių lygmens pakeitimams.

```php
use Pitmaster\Diff\WordDiff;

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