Różnice
Pitmaster oblicza różnice w ujednoliconym formacie git. Silnik różnic obsługuje wiele algorytmów, formatowanie ujednoliconych różnic, wykrywanie plików binarnych i rekursywne porównywanie na poziomie drzew.
Dla zmodyfikowanego pliku tekstowego w trybie 100644, format() generuje te same bajty co git diff. Obecnie pozostałe przypadki są formatowane inaczej (#3):
- Nowe i usunięte pliki nie mają wiersza
new file mode/deleted file mode, wierszaindexani/dev/null: obie strony są oznaczone jakoa/<path>ib/<path>, a zakres fragmentu pustej strony jest zapisywany jako-1,0lub+1,0tam, gdzie git zapisuje-0,0lub+0,0. - Wiersz
indexzawsze kończy się na100644, niezależnie od trybu pliku. - Zmiany dotyczące wyłącznie trybu (na przykład
chmod +x) nie dają wyniku. - Pliki binarne wyświetlają
Binary files differbez wierszaindex, podczas gdy git wyświetlaBinary files a/<path> and b/<path> differ. - Zmiany nazw są pokazywane jako jeden wpis
diff --git a/<old> b/<new>z różnicą zawartości, bez wierszysimilarity index,rename fromanirename to.
Operacje na różnicach
Niezatwierdzone zmiany (drzewo robocze a indeks)
$diffs = $repo->diff();
foreach ($diffs as $diff) {
echo $diff->format();
}
Porównuje każdy plik w indeksie z jego bieżącym stanem w drzewie roboczym. Wykrywa modyfikacje, usunięcia i pliki binarne.
Zmiany w indeksie (indeks a HEAD)
$diffs = $repo->diffStaged();
foreach ($diffs as $diff) {
echo $diff->format();
}
Porównuje bieżący indeks z drzewem commita HEAD. Pokazuje, co zostanie uwzględnione w następnym commicie. Usunięte i dodane pliki o podobnej zawartości są zgłaszane jako jeden wpis zmiany nazwy. Przed pierwszym commitem nie ma HEAD, więc wynik jest pusty (#5).
Obecnie dopasowywanie par przy zmianie nazw obejmuje też niezwiązane, jednoliniowe pliki, ponieważ końcowy pusty wiersz jest liczony jako wspólna zawartość (#4).
Różnice między drzewami
$a = $repo->readObject($repo->resolve('HEAD~1')->hex)->tree;
$b = $repo->head()->tree;
$diffs = $repo->diffTree($a, $b);
Porównuje rekurencyjnie dwa drzewa. Przekaż identyfikatory drzew: identyfikatory commitów nie są rozwijane do drzew, więc wynik jest pusty. Ten sam silnik TreeDiff obsługuje diffStaged(), show() i logPath().
Filtrowanie według ścieżki
$diffs = $repo->diff('src/specific-file.php');
Specyfikacja ścieżki to dokładna ścieżka do pliku. diffStaged() przyjmuje ten sam argument, ale obecnie go ignoruje, więc zawsze zwraca wszystkie pliki w indeksie (#5).
Wybór algorytmu
$diffs = $repo->diff(null, 'patience');
$diffs = $repo->diffStaged(null, 'histogram');
$diffs = $repo->diffTree($a, $b, 'minimal');
Prawidłowe nazwy to myers (domyślna), patience, histogram i minimal. Każda inna nazwa powoduje wyjątek InvalidArgumentException.
Struktura DiffResult
Każdy DiffResult reprezentuje różnice w pojedynczym pliku.
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'
}
}
}
Sformatowany wynik
echo $diff->format();
Generuje wynik w ujednoliconym formacie różnic. W przypadku zmodyfikowanego pliku tekstowego odpowiada on 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()
{
Sprawdzanie zmian
if ($diff->hasChanges()) {
// File was modified (or is binary with changes)
}
Struktura fragmentów
Każdy Hunk reprezentuje ciągły obszar zmian wraz z wierszami kontekstu.
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 @@"
Algorytmy różnic
Pitmaster implementuje cztery algorytmy różnic. Domyślnym jest Myers.
Różnice Myersa
Standardowy algorytm O(ND), taki sam jak domyślnie używany przez git. Generuje minimalne skrypty edycji.
use Pitmaster\Diff\MyersDiff;
$hunks = MyersDiff::diff($oldContent, $newContent);
Metoda diff() przyjmuje dwa ciągi znaków i zwraca tablicę obiektów Hunk. Dzieli dane wejściowe w miejscach nowych wierszy, oblicza najkrótszy skrypt edycji i grupuje zmiany w fragmenty z 3 wierszami kontekstu (tak jak domyślnie w git).
Różnice cierpliwe
Zapewnia lepsze strukturalne różnice w kodzie. Najpierw dopasowuje unikatowe wiersze, a potem wypełnia luki między nimi.
use Pitmaster\Diff\PatienceDiff;
$hunks = PatienceDiff::diff($oldContent, $newContent);
Różnice histogramowe
Odmiana algorytmu cierpliwego, która lepiej radzi sobie z powtarzającymi się wierszami. Używana przez JGit i Eclipse.
use Pitmaster\Diff\HistogramDiff;
$hunks = HistogramDiff::diff($oldContent, $newContent);
Minimalne różnice
Generuje najmniejsze możliwe różnice (najmniej zmienionych wierszy), kosztem większej liczby obliczeń.
use Pitmaster\Diff\MinimalDiff;
$hunks = MinimalDiff::diff($oldContent, $newContent);
Wykrywanie plików binarnych
Pitmaster traktuje zawartość jako binarną, jeśli w pierwszych 8192 bajtach znajduje się bajt NUL (git sprawdza pierwsze 8000).
if (MyersDiff::isBinary($content)) {
// Binary file, skip line-level diff
}
Pliki binarne dają obiekt DiffResult z $binary = true i pustą tablicą $hunks. Sformatowany wynik to:
diff --git a/image.png b/image.png
Binary files differ
Kolorowanie wyniku
CLI używa ColorDiff do wyświetlania w terminalu z kolorami ANSI.
use Pitmaster\Diff\ColorDiff;
$colorized = ColorDiff::colorize($diff->format());
echo $colorized;
- Dodane wiersze (
+) są wyświetlane na zielono - Usunięte wiersze (
-) są wyświetlane na czerwono - Nagłówki fragmentów (
@@) są wyświetlane na turkusowo - Nagłówki plików (
diff --git,index,---,+++) są wyświetlane pogrubioną czcionką
pitmaster diff zawsze koloruje wynik, także gdy jest on przekierowany potokiem. pitmaster show koloruje go tylko wtedy, gdy stdout jest terminalem.
Różnice między drzewami (wewnętrzne)
Klasa TreeDiff rekurencyjnie porównuje dwa obiekty drzewa, tworząc DiffResult dla każdego zmienionego pliku.
use Pitmaster\Diff\TreeDiff;
$treeDiff = new TreeDiff($repo->objectDatabase());
$diffs = $treeDiff->diff($oldTreeId, $newTreeId);
Różnice między drzewami obsługują:
- Dodane pliki (obecne tylko w nowym drzewie)
- Usunięte pliki (obecne tylko w starym drzewie)
- Zmodyfikowane pliki (ta sama ścieżka, inny skrót bloba)
- Rekurencyjne porównywanie podkatalogów
- Dopasowywanie par plików usuniętych i dodanych przy zmianie nazwy (dokładne dopasowanie skrótu lub co najmniej 50% wspólnych wierszy)
Wpisy z niezmienionym skrótem są pomijane, więc sama zmiana trybu nie daje wyniku.
Różnice słowne
Do wykrywania zmian pojedynczych słów w wierszach.
use Pitmaster\Diff\WordDiff;
$result = WordDiff::diff('the quick fox', 'the slow fox');
// 'the [-quick-]{+slow+} fox'