Vai al contenuto

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

PHP
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/HEAD contenente ref: refs/heads/main
  • .git/hooks/, .git/info/exclude e .git/description
  • .git/config con 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

PHP
$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:

  1. Legge il contenuto del file dall'albero di lavoro
  2. Crea un oggetto Blob e ne calcola l'hash
  3. Scrive il blob in .git/objects/ (compresso con zlib)
  4. Aggiorna la voce dell'indice per quel percorso con il nuovo hash e i metadati del file

remove

PHP
$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

PHP
$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

PHP
$commitId = $repo->commit('Fix null pointer bug');
echo $commitId->hex;

Il processo di commit:

  1. 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.
  2. Determinare il genitore: il commit HEAD corrente diventa il genitore. I commit radice (il primo commit di un repository) non hanno genitori.
  3. Determinare l'autore: viene ricavato dalle variabili d'ambiente PITMASTER_AUTHOR_* e GIT_AUTHOR_*, poi dalle costanti PITMASTER_AUTHOR_NAME/PITMASTER_AUTHOR_EMAIL, poi da .git/config (user.name/user.email), infine da Pitmaster <pitmaster@localhost>. Il committer viene determinato nello stesso modo.
  4. Scrivere l'oggetto commit: il contenuto del commit (tree, parent, author, committer, messaggio) viene serializzato, sottoposto a hash e scritto.
  5. 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

PHP
$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:

Shell
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

PHP
// 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

PHP
$repo->deleteBranch('feature/old');

Cambiare branch

PHP
$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

PHP
if ($repo->isBranchMerged('feature/done')) {
    $repo->deleteBranch('feature/done');
}

Gestione dei tag

Tag leggero

PHP
$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

PHP
$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

PHP
$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

PHP
$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

PHP
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

PHP
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

PHP
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

PHP
// 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

PHP
// 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

PHP
// 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.