Git Object Model & DAG — Git

Di balik perintah Git yang sehari-hari kamu pakai, ada model data yang elegan. Memahami ini membuat perintah Git masuk akal. Struktur folder .git/: .git/ HEAD…

Di dalam folder .git, Git menyimpan semuanya sebagai object, dan tiap object dinamai dengan hash dari isinya. Hash itu seperti sidik jari: isi yang sama selalu menghasilkan sidik jari yang sama, dan beda satu huruf saja sidik jarinya berubah total. Karena namanya diambil dari isi, Git gak pernah menyimpan isi yang sama dua kali.

🧪 Tebakan cepat: kamu bikin 2 commit. Di commit kedua cuma app.js yang berubah, README.md tetap. Ada berapa salinan isi README.md yang disimpan Git? Tebak dulu, jawabannya ada di bagian "Commit menyimpan snapshot, bukan diff".

Hash: nama dari isi

Repository latihan ini berisi README.md (isinya # Object Model) dan app.js.

$ git hash-object README.md
e6962494240ce890906939be986e7c9a196f20a0

Empat jenis object

Object Isinya Di repo ini
blob isi satu file, tanpa nama isi README.md, isi app.js
tree daftar nama file dan folder, masing-masing dengan hash blob atau tree-nya isi folder proyek
commit hash tree, hash parent, author, waktu, dan pesan initial, update
tag penunjuk ke satu commit, plus nama pembuat dan pesan (annotated tag) dibahas di pelajaran Git Tag

git cat-file -p menampilkan isi object apa pun. Ini repo latihan setelah dua commit: initial, lalu echo added >> app.js dan commit update.

$ git cat-file -p HEAD
tree f42ae588e355b1868af494346ae690c501821376
parent 24f0fbab243182bc80947f22cd64795997a2342d
author Budi <[email protected]> 1767225660 +0700
committer Budi <[email protected]> 1767225660 +0700

update
$ git cat-file -p f42ae58
100644 blob e6962494240ce890906939be986e7c9a196f20a0	README.md
100644 blob 954567f8f8a8fd5349f30d8d5d685f6eba6703af	app.js
$ git cat-file -p 954567f
console.log(1)
added

Commit menyimpan snapshot, bukan diff

Tree kedua commit itu:

Commit initial (24f0fba) Commit update (b599099)
tree 66f43bf f42ae58
README.md e696249 e696249
app.js e14c4f2 954567f

Tiap commit menyimpan snapshot lengkap: tree yang menyebut semua file. Tapi isi README.md gak berubah, jadi hash-nya sama, dan kedua tree menunjuk blob yang sama. Isinya cuma disimpan sekali. Itu jawaban tebakannya: satu. Total object-nya 7: 3 blob, 2 tree, 2 commit.

git diff dan git show menghitung perubahan saat itu juga, dengan membandingkan dua snapshot. Supaya hemat tempat, belakangan Git memadatkan object ke packfile, tapi model datanya tetap snapshot.

Branch dan HEAD cuma penunjuk

$ cat .git/refs/heads/main
b599099245eff68a5dfc714169941a4885e7242c
$ cat .git/HEAD
ref: refs/heads/main

🤔 Kenapa riwayatnya disebut DAG?

Tiap commit menunjuk parent-nya, gak pernah anaknya. Commit hasil merge punya dua parent. Panahnya selalu ke masa lalu, jadi gak mungkin berputar balik: graf berarah tanpa siklus, Directed Acyclic Graph (DAG). Hash menjaminnya: hash commit dihitung dari hash parent-nya, jadi sebuah commit gak bisa menunjuk commit yang dibuat sesudahnya.

⚠️ Jebakan yang sering ketemu

TL;DR: Git menyimpan semuanya sebagai object yang dinamai hash SHA-1 dari isinya (40 karakter, biasanya ditulis 7). Ada 4 jenis: blob (isi file), tree (daftar nama file dengan hash-nya), commit (tree, parent, author, waktu, pesan), dan tag (annotated tag). Commit menyimpan snapshot lengkap, tapi isi yang sama cuma disimpan sekali. Branch adalah pointer ke commit, file kecil di .git/refs/heads/ berisi satu hash, dan .git/HEAD berisi ref ke branch aktif, ref: refs/heads/main. git cat-file -p menampilkan isi object apa pun.

Yang akan kamu pelajari