Git objektai
Viskas git saugykloje saugoma kaip objektas. Yra keturi tipai: blob objektai (failų turinys), medžių objektai (katalogų sąrašai), pakeitimai (momentinės kopijos su metaduomenimis) ir žymos (anotuotos nuorodos). Kiekvienas objektas identifikuojamas pagal jo turinio SHA-1 maišą.
Objektų tipai
Blob
Blob saugo neapdorotą failo turinį be metaduomenų (be failo pavadinimo ir teisių).
use Pitmaster\Object\Blob;
// Create from content
$blob = Blob::fromContent('Hello, world!');
echo $blob->content; // 'Hello, world!'
echo $blob->size(); // 13
echo $blob->id->hex; // SHA-1 hash
echo $blob->type->value; // 'blob' (the property is ObjectType::Blob)
Tree
Tree yra katalogų sąrašas. Kiekvienas įrašas turi režimą, pavadinimą ir maišą, nurodančią blob arba žemesnio lygio tree.
use Pitmaster\Object\Tree;
use Pitmaster\Object\TreeEntry;
// Read a tree
$tree = $repo->readObject($treeHash);
foreach ($tree->entries as $entry) {
echo "{$entry->mode} {$entry->name} {$entry->hash->hex}\n";
}
// Look up a specific entry
$entry = $tree->entry('README.md');
// Create a tree (entries already in git's sort order)
$entries = [
new TreeEntry('100644', 'README.md', $blobId),
new TreeEntry('100755', 'deploy.sh', $execBlobId),
new TreeEntry('40000', 'src', $subtreeId),
];
$tree = Tree::fromEntries($entries);
Tree::fromEntries() įrašo pateiktus įrašus nurodyta tvarka ir režimų eilutes tiksliai taip, kaip jos pateiktos, todėl pirmiausia jas surikiuokite, o katalogų režimus nurodykite kaip 40000. Tree, įrašytas naudojant 040000 arba kita tvarka, turės kitokią maišą nei git, o git fsck --strict pateikia režimą su nuliais priekyje.
TreeEntry
TreeEntry yra tik skaitomas reikšmės objektas:
use Pitmaster\Object\TreeEntry;
$entry->mode; // '100644', '100755', '40000', '120000', '160000'
$entry->name; // Filename
$entry->hash; // ObjectId
// Type checks
$entry->isBlob(); // regular or executable file (mode 10xxxx)
$entry->isExecutable(); // mode 100755
$entry->isTree(); // mode 40000 (also accepts 040000)
$entry->isSymlink(); // mode 120000
$entry->isGitlink(); // mode 160000 (submodule)
Režimų reikšmės:
| Režimas | Reikšmė |
|---|---|
100644 |
Įprastas failas |
100755 |
Vykdomasis failas |
40000 |
Katalogas (tree); git ls-tree rodo kaip 040000 |
120000 |
Simbolinė nuoroda |
160000 |
Gitlink (submodulis) |
Tree įrašai rūšiuojami pagal pavadinimą; lyginant katalogų pavadinimus laikoma, kad jų gale yra /.
Commit
Commit susieja tree su jo istorija ir metaduomenimis.
use Pitmaster\Object\Commit;
$commit = $repo->head();
$commit->id; // ObjectId
$commit->tree; // ObjectId of the tree
$commit->parents; // array of ObjectId (zero for root, one for normal, two+ for merge)
$commit->author; // 'Name <email> timestamp timezone'
$commit->committer; // 'Name <email> timestamp timezone'
$commit->message; // Full commit message
$commit->isMerge(); // true if two or more parents
Commit turinio kūrimas
$content = Commit::buildContent(
tree: $treeId,
parents: [$parentId],
author: 'Jane <jane@example.com> 1700000000 +0000',
committer: 'Jane <jane@example.com> 1700000000 +0000',
message: "Add feature\n",
);
Neapdorotas commit formatas:
tree <hex hash>\n
parent <hex hash>\n (zero or more)
author <name> <<email>> <timestamp> <tz>\n
committer <name> <<email>> <timestamp> <tz>\n
\n
<message>
Tag
Anotuoti tag yra objektai su metaduomenimis.
use Pitmaster\Object\Tag;
$tag = $repo->readObject($tagHash);
$tag->object; // ObjectId of the target
$tag->objectType; // ObjectType enum (ObjectType::Commit, ...)
$tag->name; // Tag name
$tag->tagger; // 'Name <email> timestamp timezone'
$tag->message; // Tag message
Neapdorotas tag formatas:
object <hex hash>\n
type commit\n
tag <name>\n
tagger <name> <<email>> <timestamp> <tz>\n
\n
<message>
ObjectId
ObjectId yra tik skaitomas reikšmės objektas, atitinkantis SHA-1 (arba SHA-256) maišą.
use Pitmaster\Object\ObjectId;
use Pitmaster\Object\ObjectType;
// From hex string
$id = ObjectId::fromHex('a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2');
// From binary (20 bytes for SHA-1, 32 for SHA-256)
$id = ObjectId::fromBinary($rawBytes);
// Compute from content
$id = ObjectId::compute(ObjectType::Blob, 'Hello, world!');
$id = ObjectId::compute(ObjectType::Blob, 'Hello, world!', 'sha256');
// Zero hash
$id = ObjectId::zero();
$id = ObjectId::zero('sha256');
// Properties
$id->hex; // 40-character hex string (64 for SHA-256)
$id->binary; // 20-byte raw binary (32 for SHA-256)
$id->algo; // 'sha1' or 'sha256'
$id->isSha256();
$id->isZero();
// Comparison
$id->equals($otherId);
Maiša apskaičiuojama pagal nesuglaudintus duomenis: sha1("{type} {size} arba SHA-256 iš tų pačių baitų. fromHex() ir fromBinary() algoritmą parenka pagal ilgį.
ObjectType išvardijimas
use Pitmaster\Object\ObjectType;
ObjectType::Blob; // 'blob'
ObjectType::Tree; // 'tree'
ObjectType::Commit; // 'commit'
ObjectType::Tag; // 'tag'
Laisvųjų objektų formatas
Laisvieji objektai saugomi kaip atskiri failai kataloge .git/objects/, suskirstyti pagal pirmuosius du jų maišos šešioliktainius simbolius.
.git/objects/a1/b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2
Failo turinys suglaudinamas naudojant zlib. Nesuglaudintas turinys:
<type> <decimal size>\0<raw content>
Pavyzdžiui, blob, kuriame yra „Hello“, saugomas taip:
zlib_encode("blob 5\0Hello")
Laisvųjų objektų skaitymas
use Pitmaster\Storage\LooseObjectStore;
$store = new LooseObjectStore('/path/to/.git/objects');
$object = $store->read($objectId);
LooseObjectStore:
- Apskaičiuoja failo kelią pagal maišą
- Perskaito failą ir išskleidžia zlib suglaudintus duomenis
- Išanalizuoja antraštę, kad gautų tipą ir dydį
- Perduoda duomenis atitinkamam analizatoriui (
Blob,Tree,Commit,Tag)
Laisvųjų objektų įrašymas
$store->write($object);
Įrašymo eiga:
- Serializavimas:
"{type} {size}\0{content}" - Naudojama objekto
id, apskaičiuota jį sukūrus (skaitant maiša patikrinama) - Suspaudimas:
zlib_encode(serialized) - Įrašymas į
.git/objects/{hash[0..1]}/{rest of hash} - Atominis įrašymas (įrašoma į laikiną failą, tada jis pervadinamas)
ObjectSerializer
ObjectSerializer tvarko objekto perdavimo formato kodavimą ir dekodavimą.
use Pitmaster\Storage\ObjectSerializer;
// Encode
$raw = ObjectSerializer::encodeRaw($object);
// "blob 5\0Hello"
$compressed = ObjectSerializer::encode($object);
// zlib-compressed form, as stored in a loose object file
// Decode
$object = ObjectSerializer::decodeRaw($raw);
$object = ObjectSerializer::decode($compressed, $expectedHex); // throws CorruptObjectException on a hash mismatch
ObjectDatabase
ObjectDatabase yra sudėtinė saugykla, kuri pirmiausia ieško laisvųjų objektų, tada paketo failuose.
use Pitmaster\Storage\ObjectDatabase;
$db = new ObjectDatabase('/path/to/.git/objects');
$object = $db->read($objectId); // Search loose, then packs
$db->write($object); // Always writes to loose
$exists = $db->exists($objectId); // Check loose, then packs
$all = $db->listAll(); // All hashes from loose + packs
Rašymas tiesiai į laisvųjų objektų saugyklą yra tyčinis. Leiskite git gc pergrupuoti objektus į paketo failus.
SHA-256 palaikymas
Pitmaster maišos algoritmą abstrahuoja per ObjectId. Pagal numatytuosius nustatymus naudojama SHA-1. SHA-256 parenkama kuriant saugyklą:
$repo = Pitmaster::init('/path/to/project', 'sha256');
./vendor/bin/pitmaster init --object-format=sha256
Taip extensions.objectformat = sha256 įrašomas į konfigūraciją. Vėliau atidarytos saugyklos formatą nuskaito iš šio įrašo, o visos objektų, tree, indekso ir nuorodų operacijos naudoja 64 simbolių šešioliktaines eilutes ir 32 baitų dvejetaines maišas. Nėra bendrojo jungiklio ar konstantos, skirtos algoritmui pakeisti.
Kuriant objektus rankiniu būdu, objekto klasėms algoritmas perduodamas kaip argumentas: Blob::fromContent($content, 'sha256'), Tree::fromEntries($entries, 'sha256'), ObjectId::compute($type, $content, 'sha256'). Pitmaster::clone() kuria SHA-1 saugyklas.
Tree įrašo dvejetainis formatas
Tree objekto turinyje kiekvienas įrašas koduojamas taip:
<octal mode as ASCII> <space> <filename> \0 <binary hash: 20 bytes SHA-1, 32 bytes SHA-256>
Pastaba: maiša yra neapdorota dvejetainė seka, o ne šešioliktainė, priešingai nei commit ir tag objektuose esančios šešioliktainės maišos.
Įrašai rūšiuojami lyginant pavadinimus taip, tarsi katalogų pavadinimų gale būtų /. Ši tvarka turi būti tiksli, kad tree maiša sutaptų su git apskaičiuota maiša.