Разлики
Pitmaster изчислява разликите във формата unified на git. Механизмът за сравнение поддържа множество алгоритми, форматиране във формат unified diff, откриване на двоични файлове и рекурсивно сравнение на ниво дърво.
За променен текстов файл с режим 100644, format() създава същите байтове като git diff. Другите случаи в момента се форматират различно (#3):
- При нови и изтрити файлове няма ред
new file mode/deleted file mode, редindexили/dev/null: и двете страни са означени катоa/<path>иb/<path>, а диапазонът на празната страна в hunk се изписва като-1,0или+1,0, докато git изписва-0,0или+0,0. - Редът
indexвинаги завършва на100644, независимо от режима на файла. - Промените само в режима (например
chmod +x) не дават резултат. - За двоичните файлове се извежда
Binary files differбез редindex, докато git извеждаBinary files a/<path> and b/<path> differ. - Преименуванията се показват като един запис
diff --git a/<old> b/<new>със сравнение на съдържанието, без редовеsimilarity index,rename fromилиrename to.
Операции за сравнение
Промени извън индекса (работно дърво спрямо индекс)
$diffs = $repo->diff();
foreach ($diffs as $diff) {
echo $diff->format();
}
Сравнява всеки файл в индекса с текущото му състояние в работното дърво. Открива промени, изтривания и двоични файлове.
Подготвени промени (индекс спрямо HEAD)
$diffs = $repo->diffStaged();
foreach ($diffs as $diff) {
echo $diff->format();
}
Сравнява текущия индекс с дървото на комита HEAD. Показва какво ще бъде включено в следващия комит. Изтрити и добавени файлове с подобно съдържание се показват като един преименуван запис. Преди първия комит няма HEAD и резултатът е празен (#5).
Съпоставянето на преименуванията в момента също съвпада с несвързани едноредови файлове, защото завършващият празен ред се брои за споделено съдържание (#4).
Сравнение дърво с дърво
$a = $repo->readObject($repo->resolve('HEAD~1')->hex)->tree;
$b = $repo->head()->tree;
$diffs = $repo->diffTree($a, $b);
Рекурсивно сравнява две дървета. Подайте идентификатори на дървета: идентификаторите на комити не се преобразуват до техните дървета и дават празен резултат. Същият механизъм TreeDiff стои зад diffStaged(), show() и logPath().
Филтриране по път
$diffs = $repo->diff('src/specific-file.php');
Спецификацията на пътя е точният път до един файл. diffStaged() приема същия аргумент, но засега го игнорира, така че винаги връща всеки подготвен файл (#5).
Избор на алгоритъм
$diffs = $repo->diff(null, 'patience');
$diffs = $repo->diffStaged(null, 'histogram');
$diffs = $repo->diffTree($a, $b, 'minimal');
Валидните имена са myers (по подразбиране), patience, histogram и minimal. Всяко друго име хвърля InvalidArgumentException.
Структура на DiffResult
Всеки DiffResult представлява разликата за един файл.
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'
}
}
}
Форматиран изход
echo $diff->format();
Създава изход във формат unified diff. За променен текстов файл съвпада с 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()
{
Проверка за промени
if ($diff->hasChanges()) {
// File was modified (or is binary with changes)
}
Структура на hunk
Всеки Hunk представлява непрекъсната област с промени и контекстни редове.
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 @@"
Алгоритми за сравнение
Pitmaster реализира четири алгоритъма за сравнение. По подразбиране се използва Myers.
Сравнение с Myers
Стандартният алгоритъм O(ND), същият като този по подразбиране в git. Създава минимални скриптове за редактиране.
use Pitmaster\Diff\MyersDiff;
$hunks = MyersDiff::diff($oldContent, $newContent);
Методът diff() приема два низа и връща масив от обекти Hunk. Разделя входа по новите редове, изчислява най-краткия скрипт за редактиране и групира промените в блокове с 3 реда контекст (както е по подразбиране в git).
Разлика по алгоритъма Patience
По-добро структурно сравнение на код. Първо съпоставя уникалните редове, а след това попълва промеждутъците между тях.
use Pitmaster\Diff\PatienceDiff;
$hunks = PatienceDiff::diff($oldContent, $newContent);
Разлика по алгоритъма Histogram
Вариант на разликата по алгоритъма Patience, който обработва по-добре повтарящите се редове. Използва се от JGit и Eclipse.
use Pitmaster\Diff\HistogramDiff;
$hunks = HistogramDiff::diff($oldContent, $newContent);
Минимална разлика
Създава възможно най-малката разлика (с най-малко променени редове) с цената на повече изчисления.
use Pitmaster\Diff\MinimalDiff;
$hunks = MinimalDiff::diff($oldContent, $newContent);
Откриване на двоични файлове
Pitmaster третира съдържанието като двоично, ако в първите му 8192 байта има NUL байт (git проверява първите 8000).
if (MyersDiff::isBinary($content)) {
// Binary file, skip line-level diff
}
За двоични файлове се създава DiffResult с $binary = true и празен масив $hunks. Форматираният изход е:
diff --git a/image.png b/image.png
Binary files differ
Цветен изход
CLI използва ColorDiff за изхода в терминала с ANSI цветове.
use Pitmaster\Diff\ColorDiff;
$colorized = ColorDiff::colorize($diff->format());
echo $colorized;
- Добавените редове (
+) са зелени - Премахнатите редове (
-) са червени - Заглавията на блоковете (
@@) са циан - Заглавията на файловете (
diff --git,index,---,+++) са получерни
pitmaster diff винаги оцветява изхода, включително когато той е пренасочен. pitmaster show оцветява само когато stdout е терминал.
Сравнение на дървета (вътрешно)
Класът TreeDiff сравнява рекурсивно два обекта дърво и създава DiffResult за всеки променен файл.
use Pitmaster\Diff\TreeDiff;
$treeDiff = new TreeDiff($repo->objectDatabase());
$diffs = $treeDiff->diff($oldTreeId, $newTreeId);
Сравнението на дървета обработва:
- Добавени файлове (налични само в новото дърво)
- Изтрити файлове (налични само в старото дърво)
- Променени файлове (същият път, различен хеш на blob)
- Рекурсивно сравнение на поддиректории
- Съпоставяне на преименувания между изтрити и добавени файлове (точно съвпадение на хеша или поне 50% общи редове)
Записите с непроменен хеш се пропускат, така че промяна само в режима не води до резултат.
Разлика на ниво думи
За промени на ниво дума в рамките на редовете.
use Pitmaster\Diff\WordDiff;
$result = WordDiff::diff('the quick fox', 'the slow fox');
// 'the [-quick-]{+slow+} fox'