Записване в хранилища
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');
Преименува файла в работното дърво, премахва стария запис от индекса и добавя новия.
Създаване на commit-и
$commitId = $repo->commit('Fix null pointer bug');
echo $commitId->hex;
Процесът на commit:
- Изграждане на дърво от индекса: плоският списък със записи в индекса се организира в йерархия от дървета (директориите стават обекти дърво, а файловете — препратки към blob-ове). Всяко дърво се записва в хранилището за обекти.
- Определяне на родителя: текущият commit HEAD става родител. Началните commit-и (първият commit в хранилище) нямат родители.
- Определяне на автора: взема се от променливите на средата
PITMASTER_AUTHOR_*иGIT_AUTHOR_*, след това от константитеPITMASTER_AUTHOR_NAME/PITMASTER_AUTHOR_EMAIL, после от.git/config(user.name/user.email) и накрая отPitmaster <pitmaster@localhost>. Комитърът се определя по същия начин. - Записване на обекта commit: съдържанието на commit-а (
tree,parent,author,committer, съобщението) се сериализира, хешира и записва. - Актуализиране на HEAD: препратката към клона, към която сочи HEAD, се актуализира с хеша на новия commit.
Hook-овете се изпълняват преди и след тези стъпки (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>, съдържащ хеша на целевия commit.
Изтриване на клон
$repo->deleteBranch('feature/old');
Превключване на клонове
$repo->checkout('feature/login');
Актуализира HEAD така, че да сочи символично към клона, нулира индекса, за да съответства на дървото при върха на клона и актуализира работното дърво.
Локалните промени в пътища, които се различават между двете дървета, спират превключването с RuntimeException. Незавършените промени във всички други проследявани файлове се заменят със съдържанието на клона, където git би ги запазил (#2). Запишете ги с commit или ги приберете със stash, преди да превключите.
Проверка дали е слято
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'));
Лекият таг е просто ref, който сочи директно към commit.
Анотиран таг
$tagId = $repo->createTag('v2.0.0', 'Release version 2.0.0');
Анотираният таг създава обект на тага (създател, съобщение и цел) и ref, който сочи към него. Създателят е самоличността на текущия committer, определена по същия начин като автора на commit.
Персонализиран създател на тага
$tagId = $repo->createTag(
'v2.0.0',
'Release version 2.0.0',
$repo->resolve('HEAD'),
'Jane Smith <jane@example.com> 1700000000 +0000',
);
Директно обновяване на refs
$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.
Записване на 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);
Нулиране
// 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);
Избиране на commit и отмяна
// Apply a commit on the current branch
$newId = $repo->cherryPick('feature~1');
// Undo a commit
$revertId = $repo->revert('HEAD~2');
И двете команди приемат всяка ревизия, която приема resolve(). Пълните хешове работят, съкратените — не.