Scrittura nei repository
Pitmaster scrive nei repository git usando gli stessi formati binari del binario canonico git. Gli oggetti vengono scritti nell'archivio di oggetti loose (compressi con zlib), l'indice viene scritto nel formato v2 (oppure v3 quando le voci richiedono flag estesi; un indice esistente mantiene la propria versione) e i riferimenti vengono scritti come file loose. I dati scritti possono essere verificati con git fsck --strict.
Inizializzazione di un repository
use Pitmaster\Pitmaster;
$repo = Pitmaster::init('/path/to/new-project');
Questo crea:
.git/objects/(archivio di oggetti vuoto).git/refs/heads/e.git/refs/tags/(directory dei riferimenti vuote).git/HEADcontenenteref: refs/heads/main.git/hooks/,.git/info/excludee.git/description.git/configcon le impostazioni predefinite
Passate 'sha256' come secondo argomento per creare un repository SHA-256: Pitmaster::init($path, 'sha256').
La configurazione predefinita non imposta core.logallrefupdates, quindi Pitmaster non registra voci nel reflog dei repository creati finché non impostate quella chiave su true (#8). I repository creati da git init la impostano già.
Preparazione dei file
add
$repo->add('src/Feature.php');
$repo->add('src/Feature.php', 'tests/FeatureTest.php', 'README.md');
Ogni argomento è un percorso di file relativo alla radice dell'albero di lavoro. Le directory e i pattern glob non vengono espansi e un file mancante genera RuntimeException. Per ogni file, Pitmaster:
- Legge il contenuto del file dall'albero di lavoro
- Crea un oggetto
Blobe ne calcola l'hash - Scrive il blob in
.git/objects/(compresso con zlib) - Aggiorna la voce dell'indice per quel percorso con il nuovo hash e i metadati del file
remove
$repo->remove('old-file.txt');
$repo->remove('-r', 'src');
$repo->remove('--cached', 'old-file.txt');
Rimuove i percorsi tracciati dall'indice e dall'albero di lavoro. Usate --cached per rimuoverli solo dall'indice oppure -r / --recursive per le directory tracciate.
mv
$repo->mv('old-name.php', 'new-name.php');
Rinomina il file nell'albero di lavoro, rimuove la vecchia voce dell'indice e ne aggiunge una nuova.
Creazione dei commit
$commitId = $repo->commit('Fix null pointer bug');
echo $commitId->hex;
Il processo di commit:
- Creare l'albero dall'indice: l'elenco piatto delle voci dell'indice viene organizzato in una gerarchia ad albero (le directory diventano oggetti tree, i file diventano riferimenti ai blob). Ogni tree viene scritto nell'archivio degli oggetti.
- Determinare il genitore: il commit HEAD corrente diventa il genitore. I commit radice (il primo commit di un repository) non hanno genitori.
- Determinare l'autore: viene ricavato dalle variabili d'ambiente
PITMASTER_AUTHOR_*eGIT_AUTHOR_*, poi dalle costantiPITMASTER_AUTHOR_NAME/PITMASTER_AUTHOR_EMAIL, poi da.git/config(user.name/user.email), infine daPitmaster <pitmaster@localhost>. Il committer viene determinato nello stesso modo. - Scrivere l'oggetto commit: il contenuto del commit (
tree,parent,author,committer, messaggio) viene serializzato, sottoposto a hash e scritto. - Aggiornare HEAD: il riferimento del branch a cui punta HEAD viene aggiornato al nuovo hash del commit.
Gli hook vengono eseguiti prima e dopo questi passaggi (pre-commit, prepare-commit-msg, commit-msg, post-commit), a meno che l'handle non sia stato aperto con ['hooks' => false]. commit() genera un errore se manca il messaggio, se l'albero è invariato rispetto a HEAD o se l'indice contiene percorsi non uniti.
Autore personalizzato
$author = 'Jane Smith <jane@example.com> 1700000000 +0000';
$commitId = $repo->commit('Add feature', $author);
Verifica con git fsck
La copertura dei test di integrazione di Pitmaster verifica gli oggetti scritti con git fsck --strict; potete eseguire la stessa verifica manualmente:
cd /path/to/repo
git fsck --strict
Se Pitmaster scrive un oggetto non valido, git fsck segnala immediatamente l'errore.
Gestione dei branch
Creare un branch
// Branch from HEAD
$repo->createBranch('feature/new-thing');
// Branch from a specific commit
$repo->createBranch('hotfix', $repo->resolve('v1.0.0'));
Crea un file di riferimento in .git/refs/heads/<name> contenente l'hash del commit di destinazione.
Eliminare un branch
$repo->deleteBranch('feature/old');
Cambiare branch
$repo->checkout('feature/login');
Aggiorna HEAD con un riferimento simbolico al branch, reimposta l'indice in modo che corrisponda all'albero della punta del branch e aggiorna l'albero di lavoro.
Le modifiche locali nei percorsi diversi tra i due alberi interrompono il checkout con un RuntimeException. Le modifiche non confermate in tutti gli altri file tracciati vengono sostituite dal contenuto del branch, nei casi in cui git le manterrebbe (#2). Eseguite il commit o mettetele da parte prima di cambiare branch.
Verificare se è stato unito
if ($repo->isBranchMerged('feature/done')) {
$repo->deleteBranch('feature/done');
}
Gestione dei tag
Tag leggero
$repo->createLightweightTag('v1.0.0'); // At HEAD
$repo->createLightweightTag('v0.9.0', $repo->resolve('HEAD~5'));
Un tag leggero è semplicemente un riferimento che punta direttamente a un commit.
Tag annotato
$tagId = $repo->createTag('v2.0.0', 'Release version 2.0.0');
Un tag annotato crea un oggetto tag (con autore del tag, messaggio e destinazione) e un riferimento che punta a esso. L'autore del tag corrisponde all'identità attuale del committer, determinata come quella dell'autore del commit.
Autore del tag personalizzato
$tagId = $repo->createTag(
'v2.0.0',
'Release version 2.0.0',
$repo->resolve('HEAD'),
'Jane Smith <jane@example.com> 1700000000 +0000',
);
Aggiornamento diretto dei riferimenti
$repo->updateRef('refs/heads/main', $commitId);
$repo->updateRef('refs/tags/latest', $commitId);
Scrittura diretta degli oggetti
Per i casi d'uso avanzati, potete scrivere oggetti senza passare per l'API di alto livello API.
Scrivere un blob
use Pitmaster\Object\Blob;
$blob = Blob::fromContent('Hello, world!');
$id = $repo->writeObject($blob);
echo $id->hex; // SHA-1 of "blob 13\0Hello, world!"
In un repository SHA-256 passa l'algoritmo: Blob::fromContent('Hello, world!', 'sha256').
Scrivere un albero
use Pitmaster\Object\Tree;
use Pitmaster\Object\TreeEntry;
use Pitmaster\Object\ObjectId;
$entries = [
new TreeEntry('100644', 'README.md', $blobId),
new TreeEntry('40000', 'src', $subtreeId),
];
$tree = Tree::fromEntries($entries);
$id = $repo->writeObject($tree);
Tree::fromEntries() scrive le voci nell'ordine indicato e le stringhe di modalità così come sono. Passale nell'ordine degli alberi di git (per nome, confrontando le directory come se il loro nome terminasse con /) e scrivi le modalità delle directory come 40000: git memorizza le modalità degli alberi senza lo zero iniziale e git fsck --strict rifiuta 040000.
Scrivere un commit
use Pitmaster\Object\Commit;
use Pitmaster\Object\ObjectId;
use Pitmaster\Object\ObjectType;
$content = Commit::buildContent(
tree: $treeId,
parents: [$parentId],
author: 'Name <email> 1700000000 +0000',
committer: 'Name <email> 1700000000 +0000',
message: "Commit message\n",
);
$commitId = ObjectId::compute(ObjectType::Commit, $content);
$commit = Commit::parse($content, $commitId);
$repo->writeObject($commit);
Reset
// Soft: move HEAD only
$repo->reset('HEAD~1', 'soft');
// Mixed: move HEAD + reset index (default)
$repo->reset('HEAD~1');
// Hard: move HEAD + reset index + reset working tree
$repo->reset('HEAD~3', 'hard');
Ripristino
// Restore a file from the index into the worktree
$repo->restore('src/File.php');
// Restore the index version from HEAD (the worktree is left alone)
$repo->restore('src/File.php', staged: true);
// Restore from a specific commit
$repo->restore('src/File.php', 'HEAD~1');
// Restore both index and worktree from a specific commit
$repo->restore('src/File.php', 'HEAD~1', staged: true, worktree: true);
Cherry-pick e revert
// Apply a commit on the current branch
$newId = $repo->cherryPick('feature~1');
// Undo a commit
$revertId = $repo->revert('HEAD~2');
Entrambi accettano qualsiasi revisione supportata da resolve(). Gli hash completi funzionano; quelli abbreviati no.