Gå til indhold

Git-objekter

Alt i et git-arkiv gemmes som et objekt. Der findes fire typer: blobs (filindhold), trees (biblioteksoversigter), commits (snapshots med metadata) og tags (kommenterede referencer). Hvert objekt identificeres ved indholdets SHA-1-hash.

Objekttyper

Blob

En blob indeholder råt filindhold uden metadata (intet filnavn, ingen tilladelser).

PHP
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

Et tree er en mappefortegnelse. Hver post har en tilstand, et navn og en hash, der peger på en blob eller et undertree.

PHP
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() skriver posterne i den angivne rækkefølge og tilstandsstrengene præcis som angivet, så sortér dem først, og skriv mappetilstande som 40000. Et tree skrevet med 040000 eller i en anden rækkefølge får en anden hash end git, og git fsck --strict rapporterer tilstanden med foranstillede nuller.

TreeEntry

TreeEntry er et skrivebeskyttet værdiobjekt:

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

Tilstandsværdier:

Tilstand Betydning
100644 Almindelig fil
100755 Eksekverbar fil
40000 Mappe (tree); vises som 040000 af git ls-tree
120000 Symbolsk link
160000 Gitlink (submodul)

Tree-poster sorteres efter navn, hvor mappenavne behandles, som om de slutter med / ved sammenligning.

Commit

En commit knytter et tree til dets historik og metadata.

PHP
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

Opbygning af commit-indhold

PHP
$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",
);

Det rå commit-format:

Kode
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

Annoterede tags er objekter med metadata.

PHP
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

Råt tag-format:

Kode
object <hex hash>\n
type commit\n
tag <name>\n
tagger <name> <<email>> <timestamp> <tz>\n
\n
<message>

ObjectId

ObjectId er et skrivebeskyttet værdiobjekt, der repræsenterer en hash af typen SHA-1 (eller SHA-256).

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

Hashen beregnes over de ukomprimerede data: sha1("{type} {size}{content}") eller SHA-256 af de samme byte. fromHex() og fromBinary() vælger algoritmen ud fra længden.

ObjectType-enum

PHP
use Pitmaster\Object\ObjectType;

ObjectType::Blob;    // 'blob'
ObjectType::Tree;    // 'tree'
ObjectType::Commit;  // 'commit'
ObjectType::Tag;     // 'tag'

Løst objektformat

Løse objekter gemmes som individuelle filer i .git/objects/, organiseret efter de første to hexadecimale tegn i deres hash.

Kode
.git/objects/a1/b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2

Filindholdet er zlib-komprimeret. Det ukomprimerede indhold er:

Kode
<type> <decimal size>\0<raw content>

For eksempel gemmes en blob med indholdet "Hello" som:

Kode
zlib_encode("blob 5\0Hello")

Læsning af løse objekter

PHP
use Pitmaster\Storage\LooseObjectStore;

$store = new LooseObjectStore('/path/to/.git/objects');
$object = $store->read($objectId);

LooseObjectStore:

  1. Beregner filstien ud fra hashen
  2. Læser og zlib-dekomprimerer filen
  3. Analyserer headeren for at udtrække type og størrelse
  4. Overdrager behandlingen til den relevante parser (Blob, Tree, Commit, Tag)

Skrivning af løse objekter

PHP
$store->write($object);

Skriveprocessen:

  1. Serialisér: "{type} {size}\0{content}"
  2. Brug objektets id, beregnet, da objektet blev opbygget (læsninger verificerer hashen)
  3. Komprimér: zlib_encode(serialized)
  4. Skriv til .git/objects/{hash[0..1]}/{rest of hash}
  5. Atomisk skrivning (skriv til en midlertidig fil, og omdøb den derefter)

ObjectSerializer

ObjectSerializer håndterer kodning og afkodning af objektets wire-format.

PHP
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 er et sammensat lager, der først søger efter løse objekter og derefter i pack-filer.

PHP
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

Gennemskrivning til løst lager er tilsigtet. Lad git gc pakke objekterne om i pack-filer.

Understøttelse af SHA-256

Pitmaster abstraherer hash-algoritmen gennem ObjectId. SHA-1 er standarden. SHA-256 vælges for hvert repository, når det oprettes:

PHP
$repo = Pitmaster::init('/path/to/project', 'sha256');
Shell
./vendor/bin/pitmaster init --object-format=sha256

Dette skriver extensions.objectformat = sha256 til konfigurationen. Repositories, der åbnes senere, læser formatet fra denne post, og alle handlinger med objekter, træer, indeks og refs bruger derefter hexadecimale strenge på 64 tegn og binære hasher på 32 byte. Der findes ingen global kontakt eller konstant for algoritmen.

Objektklasserne tager algoritmen som argument, når du selv opbygger objekter: Blob::fromContent($content, 'sha256'), Tree::fromEntries($entries, 'sha256'), ObjectId::compute($type, $content, 'sha256'). Pitmaster::clone() opretter SHA-1-repositories.

Binært format for tree-poster

I indholdet af et tree-objekt kodes hver post som:

Kode
<octal mode as ASCII> <space> <filename> \0 <binary hash: 20 bytes SHA-1, 32 bytes SHA-256>

Bemærk: Hashen er rå binær, ikke hex, i modsætning til hex-hashene i commit- og tag-objekter.

Poster sorteres ved at sammenligne navne, som om mapper har et afsluttende /. Sorteringsrækkefølgen skal være præcis, for at tree-hashen matcher git-beregningen.