Aller au contenu

Écriture dans les dépôts

Pitmaster écrit dans les dépôts git en utilisant les mêmes formats binaires que le binaire canonique git. Les objets sont écrits dans le magasin d’objets libres (compressés avec zlib), l’index est écrit au format v2 (ou v3 lorsque les entrées nécessitent des indicateurs étendus ; un index existant conserve sa version), et les références sont écrites dans des fichiers libres. Les données écrites peuvent être vérifiées avec git fsck --strict.

Initialiser un dépôt

PHP
use Pitmaster\Pitmaster;

$repo = Pitmaster::init('/path/to/new-project');

Cela crée :

  • .git/objects/ (magasin d’objets vide)
  • .git/refs/heads/ et .git/refs/tags/ (répertoires de références vides)
  • .git/HEAD contenant ref: refs/heads/main
  • .git/hooks/, .git/info/exclude et .git/description
  • .git/config avec les paramètres par défaut

Passez 'sha256' comme deuxième argument pour créer un dépôt SHA-256 : Pitmaster::init($path, 'sha256').

La configuration par défaut ne définit pas core.logallrefupdates ; Pitmaster n’enregistre donc aucune entrée de reflog dans un dépôt qu’il a créé tant que vous ne définissez pas cette clé sur true (#8). Les dépôts créés par git init la définissent déjà.

Ajouter des fichiers à l’index

add

PHP
$repo->add('src/Feature.php');
$repo->add('src/Feature.php', 'tests/FeatureTest.php', 'README.md');

Chaque argument est un chemin de fichier relatif à la racine de l’arbre de travail. Les répertoires et les motifs glob ne sont pas développés, et un fichier manquant déclenche RuntimeException. Pour chaque fichier, Pitmaster :

  1. Lit le contenu du fichier dans l’arbre de travail
  2. Crée un objet Blob et calcule son hachage
  3. Écrit le blob dans .git/objects/ (compressé avec zlib)
  4. Met à jour l’entrée d’index de ce chemin avec le nouveau hachage et les métadonnées du fichier

remove

PHP
$repo->remove('old-file.txt');
$repo->remove('-r', 'src');
$repo->remove('--cached', 'old-file.txt');

Supprime les chemins suivis de l’index et de l’arbre de travail. Utilisez --cached pour supprimer uniquement de l’index, ou -r / --recursive pour les répertoires suivis.

mv

PHP
$repo->mv('old-name.php', 'new-name.php');

Renomme le fichier dans l’arbre de travail, supprime l’ancienne entrée d’index et ajoute la nouvelle.

Créer des commits

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

Étapes de création d’un commit :

  1. Créer l’arbre à partir de l’index : la liste à plat des entrées d’index est organisée en une hiérarchie d’arbres (les répertoires deviennent des objets arbre, les fichiers des références de blob). Chaque arbre est écrit dans le magasin d’objets.
  2. Déterminer le parent : le commit HEAD actuel devient le parent. Les commits racine (premier commit d’un dépôt) n’ont pas de parent.
  3. Déterminer l’auteur : l’auteur est défini par les variables d’environnement PITMASTER_AUTHOR_* et GIT_AUTHOR_*, puis par les constantes PITMASTER_AUTHOR_NAME/PITMASTER_AUTHOR_EMAIL, puis par .git/config (user.name/user.email), et enfin par Pitmaster <pitmaster@localhost>. Le committer est déterminé de la même manière.
  4. Écrire l’objet commit : le contenu du commit (tree, parent, author, committer, message) est sérialisé, haché et écrit.
  5. Mettre à jour HEAD : la référence de branche vers laquelle pointe HEAD est mise à jour avec le nouveau hachage du commit.

Les hooks s’exécutent autour de ces étapes (pre-commit, prepare-commit-msg, commit-msg, post-commit), sauf si le handle a été ouvert avec ['hooks' => false]. commit() déclenche une erreur si le message est manquant, si l’arbre est inchangé par rapport à HEAD ou si l’index contient des chemins non fusionnés.

Auteur personnalisé

PHP
$author = 'Jane Smith <jane@example.com> 1700000000 +0000';
$commitId = $repo->commit('Add feature', $author);

Vérifier avec git fsck

La couverture d’intégration de Pitmaster vérifie les objets écrits par rapport à git fsck --strict, et vous pouvez effectuer la même vérification manuellement :

Shell
cd /path/to/repo
git fsck --strict

Si Pitmaster écrit un objet invalide, git fsck signalera immédiatement l’erreur.

Gérer les branches

Créer une branche

PHP
// Branch from HEAD
$repo->createBranch('feature/new-thing');

// Branch from a specific commit
$repo->createBranch('hotfix', $repo->resolve('v1.0.0'));

Crée un fichier de référence à l’emplacement .git/refs/heads/<name> contenant le hachage du commit cible.

Supprimer une branche

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

Changer de branche

PHP
$repo->checkout('feature/login');

Met à jour HEAD pour qu’il pointe vers une référence symbolique vers la branche, réinitialise l’index pour qu’il corresponde à l’arbre de la pointe de la branche, puis met à jour l’arbre de travail.

Les modifications locales dans les chemins qui diffèrent entre les deux arbres interrompent le checkout avec une RuntimeException. Les modifications non validées dans tous les autres fichiers suivis sont remplacées par le contenu de la branche, là où git les conserverait (#2). Validez-les ou mettez-les de côté avant de changer de branche.

Vérifier si une branche a été fusionnée

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

Gérer les tags

Tag léger

PHP
$repo->createLightweightTag('v1.0.0');                          // At HEAD
$repo->createLightweightTag('v0.9.0', $repo->resolve('HEAD~5'));

Un tag léger est simplement une référence qui pointe directement vers un commit.

Tag annoté

PHP
$tagId = $repo->createTag('v2.0.0', 'Release version 2.0.0');

Un tag annoté crée un objet tag (avec un tagueur, un message et une cible) ainsi qu’une référence vers celui-ci. Le tagueur correspond à l’identité du committer actuel, déterminée comme pour l’auteur du commit.

Tagueur personnalisé

PHP
$tagId = $repo->createTag(
    'v2.0.0',
    'Release version 2.0.0',
    $repo->resolve('HEAD'),
    'Jane Smith <jane@example.com> 1700000000 +0000',
);

Mettre à jour directement les références

PHP
$repo->updateRef('refs/heads/main', $commitId);
$repo->updateRef('refs/tags/latest', $commitId);

Écrire directement des objets

Pour les cas d’utilisation avancés, vous pouvez écrire des objets sans passer par l’API de haut niveau.

Écrire 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!"

Dans un dépôt SHA-256, passez l’algorithme : Blob::fromContent('Hello, world!', 'sha256').

Écrire un arbre

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() écrit les entrées dans l’ordre fourni et conserve les chaînes de mode indiquées. Passez-les dans l’ordre des arbres git (par nom, en considérant que le nom des répertoires se termine par /) et écrivez les modes des répertoires sous la forme 40000 : git stocke les modes d’arbre sans le zéro initial, et git fsck --strict rejette 040000.

Écrire 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);

Réinitialiser

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');

Restaurer

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);

Sélectionner un commit et annuler

PHP
// Apply a commit on the current branch
$newId = $repo->cherryPick('feature~1');

// Undo a commit
$revertId = $repo->revert('HEAD~2');

Les deux acceptent toute révision prise en charge par resolve(). Les hachages complets fonctionnent, mais pas les hachages abrégés.