Diff
Pitmaster calculează diferențe în formatul unificat al lui git. Motorul de diferențe acceptă mai mulți algoritmi, formatarea diff-ului unificat, detectarea fișierelor binare și compararea recursivă la nivel de arbore.
Pentru un fișier text modificat cu modul 100644, format() produce aceiași octeți ca git diff. Celelalte cazuri sunt formatate diferit momentan (#3):
- Fișierele noi și cele șterse nu au nicio linie
new file mode/deleted file mode, nicio linieindexși nicio/dev/null: ambele părți sunt etichetatea/<path>șib/<path>, iar intervalul secțiunii de modificări de pe partea goală este scris ca-1,0sau+1,0, acolo unde git scrie-0,0sau+0,0. - Linia
indexse termină întotdeauna cu100644, indiferent de modul fișierului. - Modificările doar de mod (de exemplu
chmod +x) nu produc niciun rezultat. - Fișierele binare afișează
Binary files differfără o linieindex, în timp ce git afișeazăBinary files a/<path> and b/<path> differ. - Redenumirile sunt afișate ca o singură intrare
diff --git a/<old> b/<new>cu o diferență de conținut, fără liniisimilarity index,rename fromsaurename to.
Operații Diff
Modificări nestagiate (arbore de lucru față de index)
$diffs = $repo->diff();
foreach ($diffs as $diff) {
echo $diff->format();
}
Compară fiecare fișier din index cu starea sa actuală din arborele de lucru. Detectează modificări, ștergeri și fișiere binare.
Modificări stagiate (index față de HEAD)
$diffs = $repo->diffStaged();
foreach ($diffs as $diff) {
echo $diff->format();
}
Compară indexul actual cu arborele commitului HEAD. Arată ce va fi inclus în următorul commit. Fișierele șterse și adăugate cu conținut similar sunt raportate ca o singură intrare redenumită. Înainte de primul commit, HEAD nu există, iar rezultatul este gol (#5).
Asocierea redenumirilor potrivește momentan și fișiere fără legătură care au o singură linie, deoarece linia goală finală este considerată conținut comun (#4).
Diferență arbore la arbore
$a = $repo->readObject($repo->resolve('HEAD~1')->hex)->tree;
$b = $repo->head()->tree;
$diffs = $repo->diffTree($a, $b);
Compară recursiv doi arbori. Transmiteți ID-urile arborilor: ID-urile commiturilor nu sunt transformate în arborii lor și produc un rezultat gol. Același motor TreeDiff stă la baza lui diffStaged(), show() și logPath().
Filtrare după cale
$diffs = $repo->diff('src/specific-file.php');
Pathspec este o cale exactă de fișier. diffStaged() acceptă același argument, dar momentan îl ignoră, așa că returnează întotdeauna toate fișierele stadiate (#5).
Alegerea unui algoritm
$diffs = $repo->diff(null, 'patience');
$diffs = $repo->diffStaged(null, 'histogram');
$diffs = $repo->diffTree($a, $b, 'minimal');
Numele valide sunt myers (implicit), patience, histogram și minimal. Orice alt nume generează InvalidArgumentException.
Structura DiffResult
Fiecare DiffResult reprezintă diferența pentru un singur fișier.
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'
}
}
}
Rezultat formatat
echo $diff->format();
Produce un rezultat diff unificat. Pentru un fișier text modificat, corespunde lui 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()
{
Verificarea modificărilor
if ($diff->hasChanges()) {
// File was modified (or is binary with changes)
}
Structura secțiunii de modificări
Fiecare Hunk reprezintă o regiune contiguă de modificări, cu linii de context.
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 Diff
Pitmaster implementează patru algoritmi diff. Algoritmul implicit este Myers.
Diff Myers
Algoritmul standard O(ND), la fel ca valoarea implicită din git. Produce scripturi de editare minimale.
use Pitmaster\Diff\MyersDiff;
$hunks = MyersDiff::diff($oldContent, $newContent);
Metoda diff() primește două șiruri și returnează o matrice de obiecte Hunk. Împarte intrarea la liniile noi, calculează cel mai scurt script de editare și grupează modificările în secțiuni cu 3 linii de context (conform valorii implicite din git).
Diff Patience
Diferențe structurale mai bune pentru cod. Potrivește mai întâi liniile unice, apoi completează spațiile dintre ele.
use Pitmaster\Diff\PatienceDiff;
$hunks = PatienceDiff::diff($oldContent, $newContent);
Diff Histogram
O variantă a diff-ului Patience care gestionează mai bine liniile repetate. Este folosită de JGit și Eclipse.
use Pitmaster\Diff\HistogramDiff;
$hunks = HistogramDiff::diff($oldContent, $newContent);
Diff Minimal
Produce cea mai mică diferență posibilă (cu cele mai puține linii modificate), cu prețul unui volum mai mare de calcul.
use Pitmaster\Diff\MinimalDiff;
$hunks = MinimalDiff::diff($oldContent, $newContent);
Detectarea fișierelor binare
Pitmaster tratează conținutul ca binar dacă acesta conține un octet NUL în primii 8192 octeți (git verifică primii 8000).
if (MyersDiff::isBinary($content)) {
// Binary file, skip line-level diff
}
Fișierele binare produc un DiffResult cu $binary = true și o matrice $hunks goală. Rezultatul formatat este:
diff --git a/image.png b/image.png
Binary files differ
Rezultat colorat
CLI folosește ColorDiff pentru rezultatul în terminal, cu culori ANSI.
use Pitmaster\Diff\ColorDiff;
$colorized = ColorDiff::colorize($diff->format());
echo $colorized;
- Liniile adăugate (
+) sunt afișate cu verde - Liniile eliminate (
-) sunt afișate cu roșu - Antetele secțiunilor de modificări (
@@) sunt afișate cu cyan - Antetele fișierelor (
diff --git,index,---,+++) sunt afișate cu caractere aldine
pitmaster diff colorează întotdeauna rezultatul, inclusiv când este redirecționat. pitmaster show îl colorează doar când stdout este un terminal.
Diff între arbori (intern)
Clasa TreeDiff compară recursiv două obiecte arbore, producând un DiffResult pentru fiecare fișier modificat.
use Pitmaster\Diff\TreeDiff;
$treeDiff = new TreeDiff($repo->objectDatabase());
$diffs = $treeDiff->diff($oldTreeId, $newTreeId);
Diff-ul între arbori gestionează:
- Fișiere adăugate (prezente doar în arborele nou)
- Fișiere șterse (prezente doar în arborele vechi)
- Fișiere modificate (aceeași cale, hash blob diferit)
- Compararea recursivă a subdirectoarelor
- Asocierea redenumirilor între fișierele șterse și cele adăugate (hash identic sau cel puțin 50% linii comune)
Intrările al căror hash nu s-a modificat sunt omise, astfel că o simplă schimbare de mod nu produce niciun rezultat.
Diff de cuvinte
Pentru modificări la nivel de cuvânt, în linie.
use Pitmaster\Diff\WordDiff;
$result = WordDiff::diff('the quick fox', 'the slow fox');
// 'the [-quick-]{+slow+} fox'