Lectura de repositorios
Pitmaster lee repositorios git analizando directamente los formatos del disco: objetos sueltos (archivos comprimidos con zlib en .git/objects/), archivos pack (.git/objects/pack/), refs (archivos en .git/refs/ y packed-refs) y el índice (.git/index).
Abrir un repositorio
use Pitmaster\Pitmaster;
$repo = Pitmaster::open('/path/to/project');
Pitmaster admite tres diseños de repositorio:
- Repositorios normales:
.gites un directorio en la raíz del proyecto. - Árboles de trabajo vinculados:
.gites un archivo que contienegitdir: <path>y apunta a.git/worktrees/<name>/. - Repositorios bare: la ruta contiene directamente
HEAD,objects/, etc.
// Detection helpers
Pitmaster::isRepository('/path'); // true for any of the above
Pitmaster::isWorktree('/path'); // true only for linked worktrees
Leer objetos
Cada dato de un repositorio git se almacena como un objeto identificado por su hash: SHA-1 (40 caracteres hexadecimales) de forma predeterminada o SHA-256 (64 caracteres hexadecimales) en repositorios creados con Pitmaster::init($path, 'sha256'). Hay cuatro tipos de objeto: blob, árbol, commit y tag.
Los métodos basados en hash siguientes requieren el hash hexadecimal completo; no se aceptan hashes abreviados.
readObject
use Pitmaster\Object\Blob;
use Pitmaster\Object\Tree;
use Pitmaster\Object\Commit;
use Pitmaster\Object\Tag;
$object = $repo->readObject('a1b2c3d4e5f6...');
match (true) {
$object instanceof Blob => handleBlob($object),
$object instanceof Tree => handleTree($object),
$object instanceof Commit => handleCommit($object),
$object instanceof Tag => handleTag($object),
};
Los objetos se buscan primero en el almacenamiento suelto y luego en los archivos pack. Las búsquedas en archivos pack usan la tabla de dispersión .idx para la búsqueda binaria O(log n).
catFile
Para recuperar contenido de forma sencilla, sin comprobar el tipo:
$content = $repo->catFile('a1b2c3d4e5f6...');
echo $content;
objectExists
if ($repo->objectExists('a1b2c3d4e5f6...')) {
// Object is in the repository
}
listObjects
$hashes = $repo->listObjects();
// ['a1b2c3d4...', 'f6e5d4c3...', ...]
Devuelve los hashes hexadecimales de todos los objetos (sueltos y empaquetados).
Trabajar con blobs
Un blob contiene el contenido sin procesar de un archivo.
$blob = $repo->readObject($hash);
echo $blob->content; // Raw file bytes
echo $blob->size(); // Content length
echo $blob->id->hex; // Object hash
Trabajar con árboles
Un árbol es un listado de directorios. Cada entrada tiene un modo, un nombre y un hash.
$tree = $repo->readObject($hash);
foreach ($tree->entries as $entry) {
echo "{$entry->mode} {$entry->name} {$entry->hash->hex}\n";
// 100644 README.md abc123...
// 40000 src def456...
// 100755 deploy.sh 789012...
if ($entry->isTree()) {
// Recurse into subdirectory (mode 40000)
} elseif ($entry->isExecutable()) {
// Executable file (mode 100755)
} elseif ($entry->isBlob()) {
// Regular file (any 10xxxx mode, so executables match too)
} elseif ($entry->isSymlink()) {
// Symbolic link (mode 120000)
} elseif ($entry->isGitlink()) {
// Submodule (mode 160000)
}
}
Trabajo con commits
Un commit vincula una instantánea del árbol con sus padres y metadatos.
$commit = $repo->head();
echo $commit->id->hex; // Full object hash
echo $commit->tree->hex; // Tree object hash
echo $commit->author; // "Name <email> timestamp tz"
echo $commit->committer; // "Name <email> timestamp tz"
echo $commit->message; // Full commit message
// Parent commits
foreach ($commit->parents as $parentId) {
$parent = $repo->readObject($parentId->hex);
}
// Merge detection
if ($commit->isMerge()) {
// Two or more parents
}
Trabajo con etiquetas
Las etiquetas anotadas son objetos con un destino, un tipo, un nombre, un etiquetador y un mensaje.
$tag = $repo->readObject($hash);
echo $tag->object->hex; // Target object hash
echo $tag->objectType->value; // 'commit', 'tree', 'blob', or 'tag'
echo $tag->name; // Tag name
echo $tag->tagger; // "Name <email> timestamp tz"
echo $tag->message; // Tag message
Lectura de referencias
HEAD actual
$commit = $repo->head();
Resuelve HEAD (siguiendo referencias simbólicas como HEAD -> refs/heads/main -> commit hash) y devuelve el objeto commit.
Rama actual
$branch = $repo->branch(); // 'main' or null if detached
Listado de ramas y etiquetas
$branches = $repo->branches(); // ['bugfix/typo', 'feature/login', 'main']
$tags = $repo->tags(); // ['v1.0.0', 'v1.1.0']
Todas las referencias
$refs = $repo->allRefs();
// [
// 'refs/heads/main' => 'abc123...',
// 'refs/heads/feature' => 'def456...',
// 'refs/tags/v1.0.0' => '789012...',
// 'refs/remotes/origin/main' => 'abc123...',
// ]
Resolución de revisiones
$id = $repo->resolve('HEAD');
$id = $repo->resolve('main');
$id = $repo->resolve('v1.0.0');
$id = $repo->resolve('HEAD~3');
$id = $repo->resolve('main^2');
$id = $repo->resolve('3f2c1e0b9d6a4f8e7c5b2a1d0e9f8c7b6a5d4e3f');
El analizador de revisiones admite los operadores ~N (ancestro) y ^N (padre), encadenados sin límite. Los hashes deben indicarse completos.
Recorrido del historial de commits
log
Los commits se devuelven primero los más recientes, ordenados por la marca de tiempo del committer.
// Last 20 commits from HEAD
$commits = $repo->log(20);
foreach ($commits as $commit) {
$short = substr($commit->id->hex, 0, 7);
echo "{$short} {$commit->message}\n";
}
log desde un commit específico
$from = $repo->resolve('feature/login');
$commits = $repo->log(10, $from);
log filtrado por ruta de archivo
$commits = $repo->logPath('src/Repository.php', 20);
Devuelve solo los commits en los que el archivo especificado cambió (se añadió, modificó, eliminó o renombró) respecto del primer padre. La ruta debe ser la ruta exacta del archivo; los directorios no coinciden. Solo se examinan los 5 * $limit commits más recientes, por lo que podrían faltar coincidencias anteriores (#7).
show
$result = $repo->show('HEAD');
$commit = $result['commit'];
$diffs = $result['diff'];
echo "Author: {$commit->author}\n";
echo "Message: {$commit->message}\n\n";
foreach ($diffs as $diff) {
echo $diff->format();
}
Detección de la rama predeterminada
$default = $repo->defaultBranch();
// Checks: remote HEAD symref -> local HEAD -> main/master fallback
Cuando se configura remote.origin.url y los procesos están habilitados, la primera comprobación envía una solicitud smart HTTP al remoto. Se ignoran los errores de red y luego se realizan las comprobaciones locales.
Ancestría de fusiones
// Is feature fully merged into main?
$merged = $repo->isBranchMerged('feature/done', 'main');
// Find the merge base of two commits
$base = $repo->mergeBase(
$repo->resolve('main'),
$repo->resolve('feature/login'),
);