Objek Git
Semua hal dalam repositori git disimpan sebagai objek. Ada empat jenis: blob (isi file), tree (daftar direktori), commit (snapshot beserta metadata), dan tag (referensi beranotasi). Setiap objek diidentifikasi oleh hash SHA-1 dari isinya.
Jenis objek
Blob
Blob menyimpan isi file mentah tanpa metadata (tanpa nama file atau izin).
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 adalah daftar direktori. Setiap entri memiliki mode, nama, dan hash yang merujuk ke blob atau subpohon.
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() menulis entri sesuai urutan yang diberikan dan string mode persis seperti yang diberikan, jadi urutkan terlebih dahulu dan tulis mode direktori sebagai 40000. Tree yang ditulis dengan 040000 atau urutan berbeda akan mendapat hash yang berbeda dari git, dan git fsck --strict melaporkan mode dengan padding nol.
TreeEntry
TreeEntry adalah objek nilai readonly:
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)
Nilai mode:
| Mode | Arti |
|---|---|
100644 |
File biasa |
100755 |
File yang dapat dieksekusi |
40000 |
Direktori (tree); ditampilkan sebagai 040000 oleh git ls-tree |
120000 |
Tautan simbolis |
160000 |
Gitlink (submodul) |
Entri tree diurutkan berdasarkan nama, dengan nama direktori diperlakukan seolah diakhiri / untuk keperluan perbandingan.
Commit
Commit menghubungkan tree dengan riwayat dan metadatanya.
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
Menyusun isi commit
$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",
);
Format commit mentah:
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
Tag beranotasi adalah objek yang memiliki metadata.
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
Format tag mentah:
object <hex hash>\n
type commit\n
tag <name>\n
tagger <name> <<email>> <timestamp> <tz>\n
\n
<message>
ObjectId
ObjectId adalah objek nilai readonly yang merepresentasikan hash SHA-1 (atau SHA-256).
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);
Hash dihitung dari data yang tidak dikompresi: sha1("{type} {size}, atau SHA-256 dari byte yang sama. fromHex() dan fromBinary() memilih algoritme berdasarkan panjangnya.
Enum ObjectType
use Pitmaster\Object\ObjectType;
ObjectType::Blob; // 'blob'
ObjectType::Tree; // 'tree'
ObjectType::Commit; // 'commit'
ObjectType::Tag; // 'tag'
Format objek lepas
Objek lepas disimpan sebagai file terpisah dalam .git/objects/, dikelompokkan berdasarkan dua karakter heksadesimal pertama dari hash-nya.
.git/objects/a1/b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2
Isi file dikompresi dengan zlib. Konten yang tidak dikompresi adalah:
<type> <decimal size>\0<raw content>
Contohnya, blob yang berisi "Hello" disimpan sebagai:
zlib_encode("blob 5\0Hello")
Membaca objek lepas
use Pitmaster\Storage\LooseObjectStore;
$store = new LooseObjectStore('/path/to/.git/objects');
$object = $store->read($objectId);
LooseObjectStore:
- Menghitung jalur file dari hash
- Membaca dan mendekompresi file dengan zlib
- Mengurai header untuk mengambil jenis dan ukuran
- Meneruskan ke pengurai yang sesuai (
Blob,Tree,Commit,Tag)
Menulis objek lepas
$store->write($object);
Proses penulisan:
- Serialisasikan:
"{type} {size}\0{content}" - Gunakan
idobjek, yang dihitung saat objek dibuat (pembacaan memverifikasi hash) - Kompresikan:
zlib_encode(serialized) - Tulis ke
.git/objects/{hash[0..1]}/{rest of hash} - Penulisan atomik (tulis ke file sementara, lalu ganti nama)
ObjectSerializer
ObjectSerializer menangani pengodean dan penguraian format wire objek.
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 adalah penyimpanan komposit yang mencari objek lepas terlebih dahulu, lalu file pack.
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
Penulisan langsung ke penyimpanan lepas memang disengaja. Biarkan git gc mengemas ulang ke dalam file pack.
Dukungan SHA-256
Pitmaster mengabstraksikan algoritme hash melalui ObjectId. SHA-1 adalah default. SHA-256 dipilih untuk setiap repositori saat dibuat:
$repo = Pitmaster::init('/path/to/project', 'sha256');
./vendor/bin/pitmaster init --object-format=sha256
Ini menulis extensions.objectformat = sha256 ke konfigurasi. Repositori yang dibuka kemudian membaca format dari entri tersebut, lalu setiap operasi objek, tree, indeks, dan ref menggunakan string heksadesimal 64 karakter dan hash biner 32 byte. Tidak ada sakelar global atau konstanta untuk algoritme tersebut.
Kelas objek menerima algoritme sebagai argumen saat Anda membuat objek sendiri: Blob::fromContent($content, 'sha256'), Tree::fromEntries($entries, 'sha256'), ObjectId::compute($type, $content, 'sha256'). Pitmaster::clone() membuat repositori SHA-1.
Format biner entri tree
Di dalam konten objek tree, setiap entri dikodekan sebagai:
<octal mode as ASCII> <space> <filename> \0 <binary hash: 20 bytes SHA-1, 32 bytes SHA-256>
Catatan: hash-nya berupa biner mentah, bukan heksadesimal, berbeda dengan hash heksadesimal pada objek commit dan tag.
Entri diurutkan dengan membandingkan nama seolah direktori memiliki akhiran /. Urutan ini harus persis agar hash tree cocok dengan hasil perhitungan git.