Git objekti
Katrs objekts git repozitorijā tiek glabāts kā atsevišķs objekts. Ir četri veidi: blob (faila saturs), koki (direktoriju saraksti), komiti (momentuzņēmumi ar metadatiem) un tagi (anotētas atsauces). Katru objektu identificē tā satura SHA-1 jaucējvērtība.
Objektu veidi
Blob
Blob satur neapstrādātu faila saturu bez metadatiem (bez faila nosaukuma un atļaujām).
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)
Koks
Koks ir direktorijas saraksts. Katram ierakstam ir režīms, nosaukums un jaucējvērtība, kas norāda uz blob vai apakškoku.
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() ieraksta vienumus norādītajā secībā un režīmu virknes tieši tādas, kā norādīts, tāpēc vispirms tās sakārtojiet un direktoriju režīmus norādiet kā 40000. Koks, kas ierakstīts ar 040000 vai citā secībā, iegūst citādu jaucējvērtību nekā git, un git fsck --strict izvada režīmu ar nullēm sākumā.
TreeEntry
TreeEntry ir tikai lasāms vērtības objekts:
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žīmu vērtības:
| Režīms | Nozīme |
|---|---|
100644 |
Parasts fails |
100755 |
Izpildāms fails |
40000 |
Direktorija (koks); git ls-tree to rāda kā 040000 |
120000 |
Simboliskā saite |
160000 |
Gitlink (apakšmodulis) |
Koka ieraksti tiek sakārtoti pēc nosaukuma, salīdzināšanas nolūkos pieņemot, ka direktoriju nosaukumu beigās ir /.
Komits
Komits sasaista koku ar tā vēsturi un metadatiem.
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
Komita satura veidošana
$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",
);
Neapstrādāta komita formāts:
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>
Tags
Anotēti tagi ir objekti ar metadatiem.
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
Neapstrādāts taga formāts:
object <hex hash>\n
type commit\n
tag <name>\n
tagger <name> <<email>> <timestamp> <tz>\n
\n
<message>
ObjectId
ObjectId ir tikai lasāms vērtības objekts, kas attēlo SHA-1 (vai SHA-256) jaucējvērtību.
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);
Jaucējvērtība tiek aprēķināta no nesaspiestajiem datiem: sha1("{type} {size} vai tādu pašu baitu SHA-256. fromHex() un fromBinary() izvēlas algoritmu pēc garuma.
ObjectType uzskaitījums
use Pitmaster\Object\ObjectType;
ObjectType::Blob; // 'blob'
ObjectType::Tree; // 'tree'
ObjectType::Commit; // 'commit'
ObjectType::Tag; // 'tag'
Atsevišķu objektu formāts
Atsevišķi objekti tiek glabāti kā atsevišķi faili mapē .git/objects/, sakārtoti pēc pirmajām divām savas jaucējvērtības heksadecimālajām rakstzīmēm.
.git/objects/a1/b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2
Faila saturs ir saspiests ar zlib. Nesaspiestais saturs ir šāds:
<type> <decimal size>\0<raw content>
Piemēram, blob, kas satur “Hello”, tiek saglabāts šādi:
zlib_encode("blob 5\0Hello")
Atsevišķu objektu nolasīšana
use Pitmaster\Storage\LooseObjectStore;
$store = new LooseObjectStore('/path/to/.git/objects');
$object = $store->read($objectId);
LooseObjectStore:
- Aprēķina faila ceļu pēc jaucējvērtības
- Nolasa un atspiež failu ar zlib
- Parsē galveni, lai iegūtu veidu un izmēru
- Nodod attiecīgajam parsētājam (
Blob,Tree,Commit,Tag)
Atsevišķu objektu ierakstīšana
$store->write($object);
Ierakstīšanas process:
- Serializēt:
"{type} {size}\0{content}" - Izmantot objekta
id, kas aprēķināts objekta izveides laikā (nolasot jaucējvērtība tiek pārbaudīta) - Saspiest:
zlib_encode(serialized) - Ierakstīt mapē
.git/objects/{hash[0..1]}/{rest of hash} - Veikt atomisku ierakstīšanu (ierakstīt pagaidu failā un pēc tam pārdēvēt)
ObjectSerializer
ObjectSerializer apstrādā objekta vadu formāta kodēšanu un dekodēšanu.
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 ir kombinēta krātuve, kas vispirms meklē atsevišķos objektus un pēc tam pakotņu failos.
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
Rakstīšana tieši atsevišķo objektu krātuvē ir apzināta izvēle. Ļaujiet git gc pārpakot objektus pakotņu failos.
SHA-256 atbalsts
Pitmaster abstrahē jaucējalgoritmu, izmantojot ObjectId. SHA-1 ir noklusējums. SHA-256 tiek izvēlēts katram repozitorijam tā izveides laikā:
$repo = Pitmaster::init('/path/to/project', 'sha256');
./vendor/bin/pitmaster init --object-format=sha256
Tādējādi konfigurācijā tiek ierakstīts extensions.objectformat = sha256. Vēlāk atvērtie repozitoriji nolasa formātu no šī ieraksta, un visas objektu, koku, indeksa un atsauču darbības pēc tam izmanto 64 rakstzīmju heksadecimālas virknes un 32 baitu bināras jaucējvērtības. Algoritmam nav globāla slēdža vai konstantes.
Veidojot objektus pašiem, objektu klases pieņem algoritmu kā argumentu: Blob::fromContent($content, 'sha256'), Tree::fromEntries($entries, 'sha256'), ObjectId::compute($type, $content, 'sha256'). Pitmaster::clone() izveido SHA-1 repozitorijus.
Koka ieraksta binārais formāts
Koka objekta saturā katrs ieraksts tiek kodēts šādi:
<octal mode as ASCII> <space> <filename> \0 <binary hash: 20 bytes SHA-1, 32 bytes SHA-256>
Piezīme: jaucējvērtība ir neapstrādāti bināri dati, nevis heksadecimāla virkne, atšķirībā no komita un taga objektu heksadecimālajām jaucējvērtībām.
Ieraksti tiek sakārtoti, salīdzinot nosaukumus tā, it kā direktorijām beigās būtu /. Šai secībai jābūt precīzai, lai koka jaucējvērtība atbilstu git aprēķinātajai.