Siirry sisältöön

Git-objektit

Kaikki git-tietovarastossa tallennetaan objekteina. Objektityyppejä on neljä: blobit (tiedostojen sisältö), puut (hakemistolistaukset), commitit (tilannevedokset metatietoineen) ja tagit (merkityt viitteet). Kunkin objektin tunnisteena on sen sisällöstä laskettu SHA-1-tiiviste.

Objektityypit

Blob

Blob sisältää tiedoston raakasisällön ilman metatietoja (ei tiedostonimeä eikä käyttöoikeuksia).

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)

Puu

Puu on hakemistolistaus. Kullakin merkinnällä on käyttötila, nimi ja tiiviste, joka viittaa blobiin tai alipuuobjektiin.

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() kirjoittaa merkinnät annetussa järjestyksessä ja käyttötilamerkkijonot täsmälleen annettuina, joten lajittele merkinnät ensin ja kirjoita hakemistojen käyttötilaksi 40000. Komennolla 040000 tai muussa järjestyksessä kirjoitettu puu saa eri tiivisteen kuin gitin puu, ja git fsck --strict raportoi nollilla täydennetyn käyttötilan.

TreeEntry

TreeEntry on vain luku -arvo-olio:

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)

Käyttötilan arvot:

Käyttötila Merkitys
100644 Tavallinen tiedosto
100755 Suoritettava tiedosto
40000 Hakemisto (puu); git ls-tree näyttää sen muodossa 040000
120000 Symbolinen linkki
160000 Gitlink (alikomponentti)

Puun merkinnät lajitellaan nimen mukaan. Vertailussa hakemistonimiä käsitellään ikään kuin niiden lopussa olisi /.

Commit

Commit yhdistää puun sen historiaan ja metatietoihin.

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

Commit-sisällön muodostaminen

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

Raakamuotoinen commit:

Koodi
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>

Tagi

Merkityt tagit ovat metatietoja sisältäviä objekteja.

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

Raakamuotoinen tagi:

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

ObjectId

ObjectId on vain luku -arvo-olio, joka edustaa SHA-1- tai SHA-256-tiivistettä.

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

Tiiviste lasketaan pakkaamattomasta datasta: sha1("{type} {size}{content}") tai SHA-256 samoista tavuista. fromHex() ja fromBinary() valitsevat algoritmin pituuden perusteella.

ObjectType-luettelotyyppi

PHP
use Pitmaster\Object\ObjectType;

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

Irrallisten objektien muoto

Irralliset objektit tallennetaan yksittäisinä tiedostoina hakemistoon .git/objects/, jaoteltuna tiivisteen kahden ensimmäisen heksamerkin mukaan.

Koodi
.git/objects/a1/b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2

Tiedoston sisältö pakataan zlib-muodossa. Pakkaamaton sisältö on seuraava:

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

Esimerkiksi "Hello"-merkkijonon sisältävä blob tallennetaan seuraavasti:

Koodi
zlib_encode("blob 5\0Hello")

Irrallisten objektien lukeminen

PHP
use Pitmaster\Storage\LooseObjectStore;

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

LooseObjectStore:

  1. Laskee tiedostopolun tiivisteestä
  2. Lukee ja purkaa tiedoston zlib-pakkauksen
  3. Jäsentää otsakkeen ja poimii tyypin sekä koon
  4. Siirtää käsittelyn sopivalle jäsentimelle (Blob, Tree, Commit, Tag)

Irrallisten objektien kirjoittaminen

PHP
$store->write($object);

Kirjoitusprosessi:

  1. Sarjallista: "{type} {size}\0{content}"
  2. Käytä objektin id-tiivistettä, joka lasketaan objektia luotaessa (luettaessa tiiviste tarkistetaan)
  3. Pakkaa: zlib_encode(serialized)
  4. Kirjoita kohteeseen .git/objects/{hash[0..1]}/{rest of hash}
  5. Kirjoita atomisesti (kirjoita väliaikaiseen tiedostoon ja nimeä se sitten uudelleen)

ObjectSerializer

ObjectSerializer käsittelee objektien siirtoformaatin koodauksen ja dekoodauksen.

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 on yhdistelmätallennus, joka etsii ensin irrallisia objekteja ja sitten pakettitiedostoja.

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

Kirjoittaminen suoraan irralliseen tallennukseen on tarkoituksellista. Anna komennon git gc pakata objektit pakettitiedostoihin.

SHA-256-tuki

Pitmaster abstrahoi tiivistealgoritmin rajapinnan ObjectId avulla. SHA-1 on oletus. SHA-256 valitaan tietovarastokohtaisesti sen luonnin yhteydessä:

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

Tämä kirjoittaa asetuksen extensions.objectformat = sha256 määritystiedostoon. Myöhemmin avatut tietovarastot lukevat muodon tästä asetuksesta, ja kaikki objekti-, puu-, indeksi- ja viiteoperaatiot käyttävät sen jälkeen 64-merkkisiä heksadesimaalimerkkijonoja ja 32 tavun binäärisiä tiivisteitä. Algoritmille ei ole yleistä vaihtoa tai vakiota.

Objektiluokille annetaan algoritmi argumenttina, kun luot objekteja itse: Blob::fromContent($content, 'sha256'), Tree::fromEntries($entries, 'sha256'), ObjectId::compute($type, $content, 'sha256'). Pitmaster::clone() luo SHA-1-tietovarastoja.

Puumerkinnän binäärimuoto

Puuobjektin sisällössä kukin merkintä koodataan seuraavasti:

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

Huomautus: tiiviste on raakabinaarimuodossa, ei heksamuodossa, toisin kuin commit- ja tagiobjektien heksatiivisteet.

Merkinnät lajitellaan vertailemalla nimiä ikään kuin hakemistojen perässä olisi /. Järjestyksen on oltava täsmälleen oikea, jotta puun tiiviste vastaa gitin laskemaa tiivistettä.