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, řádekindexani/dev/null: obě strany jsou označeny jakoa/<path>ab/<path>a rozsah bloku změn prázdné strany se zapisuje jako-1,0nebo+1,0, kde git zapisuje-0,0nebo+0,0. - Řádek
indexvždy končí znakem100644, 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 differbez řádkuindex, zatímco git vypisujeBinary 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 fromanirename to.
Operace s rozdíly
Nepřipravené změny (pracovní strom oproti indexu)
$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)
$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
$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
$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
$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.
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
echo $diff->format();
Vytváří výstup jednotného rozdílu. U upraveného textového souboru odpovídá 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 změn
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.
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.
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.
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.
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.
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).
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:
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.
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.
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ů.
use Pitmaster\Diff\WordDiff;
$result = WordDiff::diff('the quick fox', 'the slow fox');
// 'the [-quick-]{+slow+} fox'