Към съдържанието

Разлики

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.

Операции за сравнение

Промени извън индекса (работно дърво спрямо индекс)

PHP
$diffs = $repo->diff();

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

Сравнява всеки файл в индекса с текущото му състояние в работното дърво. Открива промени, изтривания и двоични файлове.

Подготвени промени (индекс спрямо HEAD)

PHP
$diffs = $repo->diffStaged();

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

Сравнява текущия индекс с дървото на комита HEAD. Показва какво ще бъде включено в следващия комит. Изтрити и добавени файлове с подобно съдържание се показват като един преименуван запис. Преди първия комит няма HEAD и резултатът е празен (#5).

Съпоставянето на преименуванията в момента също съвпада с несвързани едноредови файлове, защото завършващият празен ред се брои за споделено съдържание (#4).

Сравнение дърво с дърво

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

Рекурсивно сравнява две дървета. Подайте идентификатори на дървета: идентификаторите на комити не се преобразуват до техните дървета и дават празен резултат. Същият механизъм TreeDiff стои зад diffStaged(), show() и logPath().

Филтриране по път

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

Спецификацията на пътя е точният път до един файл. diffStaged() приема същия аргумент, но засега го игнорира, така че винаги връща всеки подготвен файл (#5).

Избор на алгоритъм

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

Валидните имена са myers (по подразбиране), patience, histogram и minimal. Всяко друго име хвърля InvalidArgumentException.

Структура на DiffResult

Всеки DiffResult представлява разликата за един файл.

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

Форматиран изход

PHP
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()
     {

Проверка за промени

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

Структура на hunk

Всеки Hunk представлява непрекъсната област с промени и контекстни редове.

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

Алгоритми за сравнение

Pitmaster реализира четири алгоритъма за сравнение. По подразбиране се използва Myers.

Сравнение с Myers

Стандартният алгоритъм O(ND), същият като този по подразбиране в git. Създава минимални скриптове за редактиране.

PHP
use Pitmaster\Diff\MyersDiff;

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

Методът diff() приема два низа и връща масив от обекти Hunk. Разделя входа по новите редове, изчислява най-краткия скрипт за редактиране и групира промените в блокове с 3 реда контекст (както е по подразбиране в git).

Разлика по алгоритъма Patience

По-добро структурно сравнение на код. Първо съпоставя уникалните редове, а след това попълва промеждутъците между тях.

PHP
use Pitmaster\Diff\PatienceDiff;

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

Разлика по алгоритъма Histogram

Вариант на разликата по алгоритъма Patience, който обработва по-добре повтарящите се редове. Използва се от JGit и Eclipse.

PHP
use Pitmaster\Diff\HistogramDiff;

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

Минимална разлика

Създава възможно най-малката разлика (с най-малко променени редове) с цената на повече изчисления.

PHP
use Pitmaster\Diff\MinimalDiff;

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

Откриване на двоични файлове

Pitmaster третира съдържанието като двоично, ако в първите му 8192 байта има NUL байт (git проверява първите 8000).

PHP
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 цветове.

PHP
use Pitmaster\Diff\ColorDiff;

$colorized = ColorDiff::colorize($diff->format());
echo $colorized;
  • Добавените редове (+) са зелени
  • Премахнатите редове (-) са червени
  • Заглавията на блоковете (@@) са циан
  • Заглавията на файловете (diff --git, index, ---, +++) са получерни

pitmaster diff винаги оцветява изхода, включително когато той е пренасочен. pitmaster show оцветява само когато stdout е терминал.

Сравнение на дървета (вътрешно)

Класът TreeDiff сравнява рекурсивно два обекта дърво и създава DiffResult за всеки променен файл.

PHP
use Pitmaster\Diff\TreeDiff;

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

Сравнението на дървета обработва:

  • Добавени файлове (налични само в новото дърво)
  • Изтрити файлове (налични само в старото дърво)
  • Променени файлове (същият път, различен хеш на blob)
  • Рекурсивно сравнение на поддиректории
  • Съпоставяне на преименувания между изтрити и добавени файлове (точно съвпадение на хеша или поне 50% общи редове)

Записите с непроменен хеш се пропускат, така че промяна само в режима не води до резултат.

Разлика на ниво думи

За промени на ниво дума в рамките на редовете.

PHP
use Pitmaster\Diff\WordDiff;

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