Запис у репозиторії
Pitmaster записує репозиторії git у тих самих двійкових форматах, що й канонічний двійковий файл git. Об’єкти записуються в сховище окремих об’єктів (стиснуті zlib), індекс записується у форматі v2 (або v3, якщо для записів потрібні розширені прапорці; наявний індекс зберігає свою версію), а посилання записуються як окремі файли. Записані дані можна перевірити за допомогою git fsck --strict.
Ініціалізація репозиторію
use Pitmaster\Pitmaster;
$repo = Pitmaster::init('/path/to/new-project');
Створюються:
.git/objects/(порожнє сховище об’єктів).git/refs/heads/та.git/refs/tags/(порожні каталоги посилань).git/HEADізref: refs/heads/main.git/hooks/,.git/info/excludeта.git/description.git/configіз налаштуваннями за замовчуванням
Передайте 'sha256' другим аргументом, щоб створити репозиторій SHA-256: Pitmaster::init($path, 'sha256').
У конфігурації за замовчуванням не задано core.logallrefupdates, тому Pitmaster не записує записи reflog у створеному ним репозиторії, доки ви не встановите для цього ключа значення true (#8). Репозиторії, створені git init, уже мають це налаштування.
Додавання файлів до індексу
додати
$repo->add('src/Feature.php');
$repo->add('src/Feature.php', 'tests/FeatureTest.php', 'README.md');
Кожен аргумент — це шлях до файлу відносно кореня робочого дерева. Каталоги й шаблони glob не розгортаються, а для відсутнього файлу виникає RuntimeException. Для кожного файлу Pitmaster:
- Читає вміст файлу з робочого дерева
- Створює об’єкт
Blobі обчислює його хеш - Записує blob-об’єкт до
.git/objects/(стискає за допомогою zlib) - Оновлює запис цього шляху в індексі новим хешем і метаданими файлу
видалити
$repo->remove('old-file.txt');
$repo->remove('-r', 'src');
$repo->remove('--cached', 'old-file.txt');
Видаляє відстежувані шляхи з індексу й робочого дерева. Використовуйте --cached, щоб видалити лише з індексу, або -r / --recursive для відстежуваних каталогів.
перемістити
$repo->mv('old-name.php', 'new-name.php');
Перейменовує файл у робочому дереві, видаляє старий запис з індексу й додає новий.
Створення комітів
$commitId = $repo->commit('Fix null pointer bug');
echo $commitId->hex;
Процес створення коміту:
- Побудова дерева з індексу: плоский список записів індексу впорядковується в ієрархію дерев (каталоги стають об’єктами дерева, файли — посиланнями на blob-об’єкти). Кожне дерево записується у сховище об’єктів.
- Визначення батьківського коміту: поточний коміт HEAD стає батьківським. Початкові коміти (перші коміти в репозиторії) батьківських комітів не мають.
- Визначення автора: дані беруться зі змінних середовища
PITMASTER_AUTHOR_*таGIT_AUTHOR_*, потім із константPITMASTER_AUTHOR_NAME/PITMASTER_AUTHOR_EMAIL, далі з.git/config(user.name/user.email), а потім ізPitmaster <pitmaster@localhost>. Автор коміту визначається так само. - Запис об’єкта коміту: вміст коміту (
tree,parent,author,committer, повідомлення) серіалізується, хешується й записується. - Оновлення HEAD: посилання на гілку, на яку вказує HEAD, оновлюється новим хешем коміту.
Навколо цих кроків виконуються перехоплювачі (pre-commit, prepare-commit-msg, commit-msg, post-commit), якщо дескриптор не відкрито з ['hooks' => false]. commit() викликає помилку, якщо повідомлення відсутнє, дерево не змінилося порівняно з HEAD або індекс містить незлиті шляхи.
Власний автор
$author = 'Jane Smith <jane@example.com> 1700000000 +0000';
$commitId = $repo->commit('Add feature', $author);
Перевірка за допомогою git fsck
Інтеграційні перевірки Pitmaster звіряють записані об’єкти з git fsck --strict, а ви можете вручну виконати таку саму перевірку:
cd /path/to/repo
git fsck --strict
Якщо Pitmaster записує некоректний об’єкт, git fsck негайно повідомить про помилку.
Керування гілками
Створення гілки
// Branch from HEAD
$repo->createBranch('feature/new-thing');
// Branch from a specific commit
$repo->createBranch('hotfix', $repo->resolve('v1.0.0'));
Створює файл посилання за шляхом .git/refs/heads/<name>, що містить хеш цільового коміту.
Видалення гілки
$repo->deleteBranch('feature/old');
Перемикання гілок
$repo->checkout('feature/login');
Оновлює HEAD як символічне посилання на гілку, скидає індекс до стану дерева на вершині гілки та оновлює робоче дерево.
Локальні зміни шляхів, що відрізняються в двох деревах, зупиняють перемикання з RuntimeException. Незбережені зміни в усіх інших відстежуваних файлах замінюються вмістом гілки; git зберіг би їх (#2). Зафіксуйте або сховайте зміни перед перемиканням.
Перевірка злиття
if ($repo->isBranchMerged('feature/done')) {
$repo->deleteBranch('feature/done');
}
Керування тегами
Легковаговий тег
$repo->createLightweightTag('v1.0.0'); // At HEAD
$repo->createLightweightTag('v0.9.0', $repo->resolve('HEAD~5'));
Легковаговий тег — це просто посилання безпосередньо на коміт.
Анотований тег
$tagId = $repo->createTag('v2.0.0', 'Release version 2.0.0');
Анотований тег створює об’єкт тегу (з автором тегу, повідомленням і цільовим об’єктом) та посилання на нього. Автором тегу є поточний автор коміту; його дані визначаються так само, як для автора коміту.
Власний автор тегу
$tagId = $repo->createTag(
'v2.0.0',
'Release version 2.0.0',
$repo->resolve('HEAD'),
'Jane Smith <jane@example.com> 1700000000 +0000',
);
Безпосереднє оновлення посилань
$repo->updateRef('refs/heads/main', $commitId);
$repo->updateRef('refs/tags/latest', $commitId);
Безпосередній запис об’єктів
Для складніших випадків використання можна записувати об’єкти без високорівневого API.
Запис blob-об’єкта
use Pitmaster\Object\Blob;
$blob = Blob::fromContent('Hello, world!');
$id = $repo->writeObject($blob);
echo $id->hex; // SHA-1 of "blob 13\0Hello, world!"
У репозиторії SHA-256 виконайте алгоритм: Blob::fromContent('Hello, world!', 'sha256').
Запис дерева
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() записує записи в заданому порядку й рядки режимів без змін. Передайте їх у порядку дерева git (за назвою; назви каталогів порівнюються так, ніби в кінці назви стоїть /) і задавайте режими каталогів як 40000: git зберігає режими дерева без початкового нуля, а git fsck --strict відхиляє 040000.
Запис коміту
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);
Скидання
// 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');
Відновлення
// 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);
Вибіркове перенесення коміту та скасування змін
// Apply a commit on the current branch
$newId = $repo->cherryPick('feature~1');
// Undo a commit
$revertId = $repo->revert('HEAD~2');
Обидві команди приймають будь-яку ревізію, яку підтримує resolve(). Повні хеші працюють, скорочені — ні.