Ugrás a tartalomhoz

Diff

Az Pitmaster a git egységes formátumában számítja ki a különbségeket. A diffmotor több algoritmust, egységes diffformázást, binárisfájl-felismerést és rekurzív, faszintű összehasonlítást támogat.

100644 módú módosított szövegfájl esetén az format() ugyanazokat a bájtokat állítja elő, mint az git diff. A többi eset formázása jelenleg eltér (#3):

  • Az új és törölt fájlokban nincs new file mode / deleted file mode sor, index sor és /dev/null sem: mindkét oldal címkéje a/<path> és b/<path>, az üres oldal hunk-tartománya pedig -1,0 vagy +1,0 alakban szerepel ott, ahol a git -0,0 vagy +0,0 formát használ.
  • Az index sor mindig 100644 végződik, a fájl módjától függetlenül.
  • A csak módot érintő módosítások (például chmod +x) nem adnak eredményt.
  • A bináris fájlok Binary files differ formában jelennek meg index sor nélkül, míg a git Binary files a/<path> and b/<path> differ formát használ.
  • Az átnevezéseket egyetlen diff --git a/<old> b/<new> bejegyzésként jeleníti meg tartalmi diffel, similarity index, rename from és rename to sorok nélkül.

Diffműveletek

Nem előkészített módosítások (munkakönyvtár az indexhez képest)

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

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

Az indexben lévő minden fájlt összehasonlít az aktuális munkakönyvtári állapotával. Felismeri a módosításokat, törléseket és bináris fájlokat.

Előkészített módosítások (index a HEAD-hez képest)

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

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

Az aktuális indexet összehasonlítja a HEAD commit fájafájával. Megmutatja, mi kerül bele a következő commitba. A hasonló tartalmú törölt és hozzáadott fájlokat egy átnevezett bejegyzésként jelenti. Az első commit előtt nincs HEAD, ezért az eredmény üres (#5).

Az átnevezések párosítása jelenleg egymástól független, egysoros fájlokat is összepárosít, mert a záró üres sort közös tartalomnak veszi (#4).

Fák összehasonlítása

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

Két fát hasonlít össze rekurzívan. Faazonosítókat adjon meg: a commitazonosítókat nem bontja fel fáikra, így üres eredményt adnak. Ugyanaz az TreeDiff motor szolgál az diffStaged(), az show() és az logPath() működésének alapjául.

Szűrés elérési út alapján

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

A pathspec egy pontos fájlelérési út. Az diffStaged() ugyanilyen argumentumot fogad, de jelenleg figyelmen kívül hagyja, ezért minden előkészített fájlt visszaad (#5).

Algoritmus kiválasztása

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

Érvényes nevek: myers (alapértelmezett), patience, histogram és minimal. Más név esetén InvalidArgumentException kivétel keletkezik.

A DiffResult felépítése

Minden DiffResult egyetlen fájl diffjét képviseli.

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

Formázott kimenet

PHP
echo $diff->format();

Egységes formátumú diffkimenetet állít elő. Módosított szövegfájl esetén megegyezik az git diff eredményével:

Kód
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()
     {

Változások ellenőrzése

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

Hunkok felépítése

Minden Hunk a módosítások összefüggő, kontextussorokat tartalmazó szakaszát jelenti.

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

Diffalgoritmusok

Az Pitmaster négy diffalgoritmust valósít meg. Az alapértelmezett a Myers-algoritmus.

Myers-féle diff

A szabványos O(ND) algoritmus, ugyanaz, mint a git alapértelmezettje. Minimális módosítási szkripteket állít elő.

PHP
use Pitmaster\Diff\MyersDiff;

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

Az diff() metódus két karakterláncot fogad, és Hunk objektumok tömbjét adja vissza. A bemenetet sortörések mentén részekre bontja, kiszámítja a legrövidebb módosítási szkriptet, majd a változásokat 3 kontextussort tartalmazó hunkokba csoportosítja (a git alapértelmezett működését követve).

Patience diff

Jobb szerkezetű diffet ad a kódhoz. Először az egyedi sorokat párosítja, majd kitölti a közöttük lévő részeket.

PHP
use Pitmaster\Diff\PatienceDiff;

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

Hisztogram diff

A patience diff egyik változata, amely jobban kezeli az ismétlődő sorokat. Az JGit és az Eclipse használja.

PHP
use Pitmaster\Diff\HistogramDiff;

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

Minimális diff

A lehető legkisebb diffet állítja elő (a lehető legkevesebb módosított sorral), több számítás árán.

PHP
use Pitmaster\Diff\MinimalDiff;

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

Bináris fájlok felismerése

Az Pitmaster akkor kezeli binárisként a tartalmat, ha annak első 8192 bájtja között NUL bájt található (a git az első 8000 bájtot ellenőrzi).

PHP
if (MyersDiff::isBinary($content)) {
    // Binary file, skip line-level diff
}

A bináris fájlok olyan DiffResult értéket adnak, amelyben az $binary = true szerepel, az $hunks tömb pedig üres. A formázott kimenet:

Kód
diff --git a/image.png b/image.png
Binary files differ

Színezett kimenet

Az CLI az ColorDiff használatával, ANSI-színekkel jeleníti meg a terminálkimenetet.

PHP
use Pitmaster\Diff\ColorDiff;

$colorized = ColorDiff::colorize($diff->format());
echo $colorized;
  • A hozzáadott sorok (+) zölden jelennek meg
  • A törölt sorok (-) pirosan jelennek meg
  • A hunkfejlécek (@@) cián színűek
  • A fájlfejlécek (diff --git, index, ---, +++) félkövéren jelennek meg

pitmaster diff mindig színez, akkor is, ha a kimenete át van irányítva. pitmaster show csak akkor színez, ha a szabványos kimenet terminálra mutat.

Fák összehasonlítása (belső)

Az TreeDiff osztály rekurzívan hasonlít össze két faobjektumot, és minden módosult fájlhoz létrehoz egy DiffResult elemet.

PHP
use Pitmaster\Diff\TreeDiff;

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

A fák összehasonlítása a következőket kezeli:

  • Hozzáadott fájlok (csak az új fában szerepelnek)
  • Törölt fájlok (csak a régi fában szerepelnek)
  • Módosított fájlok (azonos útvonal, eltérő blobhash)
  • Alkönyvtárak rekurzív összehasonlítása
  • Törölt és hozzáadott fájlok párosítása átnevezésként (azonos hash esetén, vagy ha a sorok legalább 50%-a közös)

A változatlan hashű bejegyzéseket kihagyja, ezért önmagában egy módváltozás nem eredményez kimenetet.

Szavak összehasonlítása

Sorokon belüli, szószintű változásokhoz.

PHP
use Pitmaster\Diff\WordDiff;

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