Ga naar de inhoud

Diff

Pitmaster berekent verschillen in het uniforme formaat van git. De diff-engine ondersteunt meerdere algoritmen, uniforme diff-opmaak, detectie van binaire bestanden en recursieve vergelijking op boomniveau.

Voor een gewijzigd tekstbestand met modus 100644 produceert format() dezelfde bytes als git diff. Andere gevallen worden momenteel anders opgemaakt (#3):

  • Nieuwe en verwijderde bestanden hebben geen regel new file mode / deleted file mode, geen regel index en geen /dev/null: beide zijden krijgen de aanduiding a/<path> en b/<path>, en het hunk-bereik van de lege zijde wordt geschreven als -1,0 of +1,0, terwijl git -0,0 of +0,0 schrijft.
  • De regel index eindigt altijd op 100644, ongeacht de bestandsmodus.
  • Wijzigingen in alleen de modus (bijvoorbeeld chmod +x) leveren geen resultaat op.
  • Binaire bestanden tonen Binary files differ zonder een regel index, terwijl git Binary files a/<path> and b/<path> differ toont.
  • Hernoemingen worden weergegeven als één diff --git a/<old> b/<new>-item met een inhoudsverschil, zonder regels similarity index, rename from of rename to.

Diff-bewerkingen

Niet-gefaseerde wijzigingen (werkboom versus index)

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

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

Vergelijkt elk bestand in de index met de huidige staat ervan in de werkboom. Detecteert wijzigingen, verwijderingen en binaire bestanden.

Gefaseerde wijzigingen (index versus HEAD)

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

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

Vergelijkt de huidige index met de tree van de HEAD-commit. Toont wat in de volgende commit wordt opgenomen. Verwijderde en toegevoegde bestanden met vergelijkbare inhoud worden als één hernoemd item gerapporteerd. Vóór de eerste commit bestaat er geen HEAD en is het resultaat leeg (#5).

Koppeling van hernoemde bestanden matcht momenteel ook niet-gerelateerde bestanden van één regel, omdat de afsluitende lege regel als gedeelde inhoud telt (#4).

Diff tussen trees

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

Vergelijkt twee trees recursief. Geef tree-ID's door: commit-ID's worden niet herleid tot hun trees en leveren een leeg resultaat op. Dezelfde engine TreeDiff ligt ten grondslag aan diffStaged(), show() en logPath().

Filteren op pad

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

De pathspec is één exact bestandspad. diffStaged() accepteert hetzelfde argument, maar negeert het momenteel en retourneert daarom altijd elk gefaseerd bestand (#5).

Een algoritme kiezen

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

Geldige namen zijn myers (standaard), patience, histogram en minimal. Elke andere naam gooit InvalidArgumentException.

Structuur van DiffResult

Elk DiffResult vertegenwoordigt de diff voor één bestand.

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

Opgemaakte uitvoer

PHP
echo $diff->format();

Produceert unified diff-uitvoer. Voor een gewijzigd tekstbestand komt deze overeen met git diff:

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

Controleren op wijzigingen

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

Hunk-structuur

Elk Hunk vertegenwoordigt een aaneengesloten gebied met wijzigingen en contextregels.

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

Diff-algoritmen

Pitmaster implementeert vier diff-algoritmen. Myers is de standaard.

Myers-diff

Het standaardalgoritme O(ND), hetzelfde als de standaardinstelling van git. Levert minimale bewerkingsscripts op.

PHP
use Pitmaster\Diff\MyersDiff;

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

De methode diff() neemt twee tekenreeksen en retourneert een array met Hunk-objecten. De invoer wordt opgesplitst bij regeleinden, het kortste bewerkingsscript wordt berekend en wijzigingen worden gegroepeerd in hunks met 3 contextregels (zoals de standaardinstelling van git).

Patience-diff

Zorgt voor betere structurele diffs van code. Matcht eerst unieke regels en vult daarna de tussenliggende stukken op.

PHP
use Pitmaster\Diff\PatienceDiff;

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

Histogram-diff

Een variant van de patience-diff die beter omgaat met herhaalde regels. Wordt gebruikt door JGit en Eclipse.

PHP
use Pitmaster\Diff\HistogramDiff;

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

Minimale diff

Produceert de kleinst mogelijke diff (met zo min mogelijk gewijzigde regels), ten koste van meer rekenwerk.

PHP
use Pitmaster\Diff\MinimalDiff;

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

Binaire detectie

Pitmaster behandelt inhoud als binair wanneer deze een NUL-byte bevat in de eerste 8192 bytes (git controleert de eerste 8000).

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

Binaire bestanden produceren een DiffResult met $binary = true en een lege array $hunks. De opgemaakte uitvoer is:

Code
diff --git a/image.png b/image.png
Binary files differ

Uitvoer met kleuren

De CLI gebruikt ColorDiff voor terminaluitvoer met ANSI-kleuren.

PHP
use Pitmaster\Diff\ColorDiff;

$colorized = ColorDiff::colorize($diff->format());
echo $colorized;
  • Toegevoegde regels (+) worden groen weergegeven
  • Verwijderde regels (-) worden rood weergegeven
  • Hunk-headers (@@) worden cyaan weergegeven
  • Bestandsheaders (diff --git, index, ---, +++) worden vet weergegeven

pitmaster diff kleurt altijd, ook wanneer de uitvoer wordt doorgevoerd. pitmaster show kleurt alleen wanneer stdout een terminal is.

Tree-diff (intern)

De klasse TreeDiff vergelijkt twee tree-objecten recursief en produceert een DiffResult voor elk gewijzigd bestand.

PHP
use Pitmaster\Diff\TreeDiff;

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

Tree-diff behandelt:

  • Toegevoegde bestanden (alleen aanwezig in de nieuwe tree)
  • Verwijderde bestanden (alleen aanwezig in de oude tree)
  • Gewijzigde bestanden (zelfde pad, andere blob-hash)
  • Recursieve vergelijking van submappen
  • Koppeling van hernoemingen tussen verwijderde en toegevoegde bestanden (exacte hash-match of minstens 50% gedeelde regels)

Items met een ongewijzigde hash worden overgeslagen, dus een wijziging van alleen de modus levert geen resultaat op.

Word-diff

Voor wijzigingen op woordniveau binnen regels.

PHP
use Pitmaster\Diff\WordDiff;

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