Diferencia
Pitmaster calcula diferencias en el formato unificado de git. El motor de diferencias admite varios algoritmos, formato diff unificado, detección de archivos binarios y comparación recursiva a nivel de árbol.
Para un archivo de texto modificado con el modo 100644, format() produce los mismos bytes que git diff. Actualmente, otros casos tienen un formato distinto (#3):
- Los archivos nuevos y eliminados no tienen línea
new file mode/deleted file mode, líneaindexni/dev/null: ambos lados se etiquetan comoa/<path>yb/<path>, y el rango de bloque del lado vacío se escribe como-1,0o+1,0donde git escribe-0,0o+0,0. - La línea
indexsiempre termina en100644, independientemente del modo del archivo. - Los cambios solo de modo (por ejemplo,
chmod +x) no producen resultados. - Los archivos binarios muestran
Binary files differsin una líneaindex, mientras que git muestraBinary files a/<path> and b/<path> differ. - Los renombrados aparecen como una sola entrada
diff --git a/<old> b/<new>con una diferencia de contenido, sin líneassimilarity index,rename fromnirename to.
Operaciones de diferencias
Cambios sin preparar (árbol de trabajo frente al índice)
$diffs = $repo->diff();
foreach ($diffs as $diff) {
echo $diff->format();
}
Compara cada archivo del índice con su estado actual en el árbol de trabajo. Detecta modificaciones, eliminaciones y archivos binarios.
Cambios preparados (índice frente a HEAD)
$diffs = $repo->diffStaged();
foreach ($diffs as $diff) {
echo $diff->format();
}
Compara el índice actual con el árbol del commit HEAD. Muestra lo que se incluirá en el siguiente commit. Los archivos eliminados y añadidos con contenido similar se informan como una sola entrada renombrada. Antes del primer commit no existe HEAD y el resultado está vacío (#5).
Actualmente, el emparejamiento de renombrados también relaciona archivos de una sola línea que no guardan relación, porque la línea vacía final cuenta como contenido compartido (#4).
Diferencia entre árboles
$a = $repo->readObject($repo->resolve('HEAD~1')->hex)->tree;
$b = $repo->head()->tree;
$diffs = $repo->diffTree($a, $b);
Compara dos árboles de forma recursiva. Pasa los ID de árbol: los ID de commit no se convierten a sus árboles y producen un resultado vacío. El mismo motor TreeDiff sustenta diffStaged(), show() y logPath().
Filtrar por ruta
$diffs = $repo->diff('src/specific-file.php');
El pathspec es una ruta de archivo exacta. diffStaged() acepta el mismo argumento, pero por ahora lo ignora, así que siempre devuelve todos los archivos preparados (#5).
Elegir un algoritmo
$diffs = $repo->diff(null, 'patience');
$diffs = $repo->diffStaged(null, 'histogram');
$diffs = $repo->diffTree($a, $b, 'minimal');
Los nombres válidos son myers (predeterminado), patience, histogram y minimal. Cualquier otro nombre genera InvalidArgumentException.
Estructura de DiffResult
Cada DiffResult representa la diferencia de un solo archivo.
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'
}
}
}
Salida formateada
echo $diff->format();
Genera una salida de diff unificado. Para un archivo de texto modificado, coincide con 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()
{
Comprobar si hay cambios
if ($diff->hasChanges()) {
// File was modified (or is binary with changes)
}
Estructura de los bloques
Cada Hunk representa una región continua de cambios con líneas de contexto.
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 @@"
Algoritmos de diferencias
Pitmaster implementa cuatro algoritmos de diferencias. Myers es el predeterminado.
Diferencia de Myers
El algoritmo estándar de O(ND), igual que el predeterminado de git. Genera secuencias de edición mínimas.
use Pitmaster\Diff\MyersDiff;
$hunks = MyersDiff::diff($oldContent, $newContent);
El método diff() toma dos cadenas y devuelve una matriz de objetos Hunk. Divide la entrada por saltos de línea, calcula la secuencia de edición más corta y agrupa los cambios en bloques con 3 líneas de contexto (igual que el valor predeterminado de git).
Diferencia de paciencia
Genera diferencias estructurales mejores para el código. Primero empareja las líneas únicas y luego completa los espacios entre ellas.
use Pitmaster\Diff\PatienceDiff;
$hunks = PatienceDiff::diff($oldContent, $newContent);
Diferencia de histograma
Una variante de la diferencia de paciencia que gestiona mejor las líneas repetidas. La usan JGit y Eclipse.
use Pitmaster\Diff\HistogramDiff;
$hunks = HistogramDiff::diff($oldContent, $newContent);
Diferencia mínima
Genera la diferencia más pequeña posible (con el menor número de líneas modificadas), a costa de más cálculos.
use Pitmaster\Diff\MinimalDiff;
$hunks = MinimalDiff::diff($oldContent, $newContent);
Detección de binarios
Pitmaster trata el contenido como binario si contiene un byte NUL en sus primeros 8192 bytes (git comprueba los primeros 8000).
if (MyersDiff::isBinary($content)) {
// Binary file, skip line-level diff
}
Los archivos binarios generan un DiffResult con $binary = true y una matriz $hunks vacía. La salida formateada es:
diff --git a/image.png b/image.png
Binary files differ
Salida con colores
CLI usa ColorDiff para generar una salida de terminal con colores ANSI.
use Pitmaster\Diff\ColorDiff;
$colorized = ColorDiff::colorize($diff->format());
echo $colorized;
- Las líneas añadidas (
+) se muestran en verde - Las líneas eliminadas (
-) se muestran en rojo - Los encabezados de bloque (
@@) se muestran en cian - Los encabezados de archivo (
diff --git,index,---,+++) se muestran en negrita
pitmaster diff siempre aplica colores, incluso cuando su salida se redirige. pitmaster show solo aplica colores cuando stdout es un terminal.
Diferencia entre árboles (interna)
La clase TreeDiff compara dos objetos de árbol de forma recursiva y produce un DiffResult por cada archivo modificado.
use Pitmaster\Diff\TreeDiff;
$treeDiff = new TreeDiff($repo->objectDatabase());
$diffs = $treeDiff->diff($oldTreeId, $newTreeId);
La diferencia entre árboles gestiona:
- Archivos añadidos (solo presentes en el árbol nuevo)
- Archivos eliminados (solo presentes en el árbol antiguo)
- Archivos modificados (misma ruta, hash de blob distinto)
- Comparación recursiva de subdirectorios
- Emparejamiento de renombrados entre archivos eliminados y añadidos (coincidencia exacta de hash o al menos 50 % de líneas compartidas)
Se omiten las entradas cuyo hash no cambia, por lo que un cambio de modo por sí solo no produce resultados.
Diferencia de palabras
Para cambios en línea a nivel de palabra dentro de las líneas.
use Pitmaster\Diff\WordDiff;
$result = WordDiff::diff('the quick fox', 'the slow fox');
// 'the [-quick-]{+slow+} fox'