Sepanjang course ini kita sudah menjalankan ratusan perintah Git — add, commit, branch, merge — dan menerima hasilnya begitu saja. Section penutup Hooks dan Otomasi menutup dengan pertanyaan yang belum terjawab: bagaimana Git bekerja di dalam? Mengapa hash yang tampak acak bisa menjadi identitas yang unik, dan mengapa repository tidak membengkak meski menyimpan setiap versi setiap berkas? Jawabannya berada pada satu desain: seluruh data yang Git simpan — isi berkas, struktur folder, riwayat commit, tag — hanyalah objek di dalam sebuah database. Chapter ini membuka database itu dan memperkenalkan penghuninya.
Filosofi: Satu Database Objek #
Chapter Git Directory
sudah memperlihatkan bahwa isi riwayat hidup di objects/ dan ditunjuk oleh refs/. Sekarang kita masuk lebih dalam: Git bukan penyimpan berkas bernama, melainkan database content-addressable — setiap potong data dialamatkan oleh hash yang dihitung dari isinya sendiri, sehingga isi identik selalu berakhir pada alamat yang sama. Hanya ada empat jenis objek di dalam database ini:
| Jenis objek | Isinya | Perannya |
|---|---|---|
blob | Isi berkas mentah, tanpa nama berkas | Satu versi isi satu berkas |
tree | Daftar entri: mode, hash, nama | Struktur folder pada satu titik waktu |
commit | Metadata + satu tree root + parent | Satu titik riwayat beserta pesannya |
tag | Metadata + penunjuk ke objek lain | Tag annotated lengkap dengan pembuatnya |
Karena hanya ada empat jenis ini, memahami Git berarti memahami empat struktur kecil dan cara saling merujuknya. Perintah apa pun — dari git add sampai merge paling rumit — pada akhirnya hanya membaca dan menulis keempat jenis objek itu, plus penunjuk-penunjuk refs yang akan kita bedah pada chapter References dan Refs
.
Membangun Repository Latihan #
Kita pakai repository kecil yang sama dengan pola latihan sebelumnya: dua commit dan satu tag annotated. Bangun ulang dari nol agar keluaran kita identik:
mkdir latihan-model && cd latihan-model
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf 'Toko Kopi Senja\n' > README.md
git add README.md
git commit -m "Buat toko"
mkdir src
printf 'espresso 18000\n' > src/menu.txt
git add src/menu.txt
git commit -m "Tambah daftar menu"
git tag -a v1.0.0 -m "Rilis pertama"
git log --onelineOutput yang Dihasilkan:
455518b Tambah daftar menu
1697160 Buat tokoDua commit dan satu tag — cukup untuk menghadirkan keempat jenis objek.
git cat-file: Membedah Jenis Objek #
Perintah git cat-file -t melaporkan jenis objek dari alamat mana pun. Kita uji keempat jenisnya sekaligus pada repository latihan:
git cat-file -t HEADOutput yang Dihasilkan:
commitgit cat-file -t HEAD^{tree}Output yang Dihasilkan:
treegit cat-file -t HEAD:README.mdOutput yang Dihasilkan:
blobgit cat-file -t v1.0.0Output yang Dihasilkan:
tagEmpat perintah, empat jenis: HEAD berjenis commit, tree root-nya berjenis tree, isi README.md berjenis blob, dan tag v1.0.0 yang kita buat dengan -a berjenis objek tersendiri. Notasi HEAD^{tree} berarti “tree yang ditunjuk commit HEAD”, dan HEAD:README.md berarti “objek pada path README.md di snapshot HEAD” — dua bentuk alamat yang akan sering kita pakai di sepanjang section ini. Jumlah objek totalnya bisa dihitung:
git count-objectsOutput yang Dihasilkan:
8 objects, 32 kilobytesDelapan objek untuk dua commit: dua commit, tiga tree (dua versi tree root plus satu tree untuk folder src/), dua blob, dan satu objek tag. Seluruh riwayat repository ini memang hanya segini — tidak ada berkas tersembunyi lain.
Struktur Direktori .git/objects #
Objek-objek itu tersimpan sebagai berkas lepas (loose object) di dalam .git/objects, dengan nama berkas yang dipecah dua:
ls .git/objectsOutput yang Dihasilkan:
16
35
45
58
70
c6
d4
e8
info
packDelapan nama dua karakter adalah folder — dua karakter pertama dari hash objek — sedangkan info dan pack menampung pengaturan penyimpanan. Kita buka satu folder milik blob README.md:
ls .git/objects/e8Output yang Dihasilkan:
6980e618bbec64678d440b7116f5c47af02d1aNama berkas itu adalah 38 karakter sisanya: digabungkan dengan nama foldernya terbentuk hash utuh e86980e6... — persis blob README.md yang kita periksa tadi. Pemecahan xx/38hex menjaga folder objects/ tetap rapi meski jumlah objek membengkak; pack menjadi rumah objek terkompresi yang dibahas pada chapter Packfiles
. Bandingkan alamat commit aktif dari berkas ref-nya:
cat .git/refs/heads/mainOutput yang Dihasilkan:
455518b28637c16916025256825c0986c1be377fHash tersebut identik dengan commit “Tambah daftar menu” — folder 45 di daftar objects di atas memang tempat objek commit itu tinggal. Relasi keempat jenis objek di repository ini terpetakan berikut:
Satu commit menunjuk satu tree root; tree root menunjuk blob dan tree anak; commit kedua menunjuk commit pertama sebagai parent; tag menunjuk commit. Rantai sesederhana itu menampung seluruh keadaan proyek — diagram ini adalah peta yang kita telusuri objek demi objek pada chapter berikutnya.
Semua Perintah Hanyalah Manipulasi Objek dan Refs #
Inilah insight yang mengubah cara memandang Git: karena seluruh datanya cuma objek dan penunjuk, setiap perintah sehari-hari hanyalah kombinasi operasi database sederhana:
| Perintah sehari-hari | Yang sebenarnya dikerjakan |
|---|---|
git add menu.txt | Hitung hash isi berkas, simpan objek blob, catat pasangan path-hash di index |
git commit | Tulis objek tree dari index, tulis objek commit, geser isi refs/heads/main |
git branch fitur | Tulis berkas refs/heads/fitur berisi hash saat ini |
git tag -a v1.0.0 | Tulis objek tag, tulis berkas refs/tags/v1.0.0 menunjuknya |
git switch fitur | Tulis ulang berkas HEAD agar menunjuk refs/heads/fitur |
Dokumentasi resmi menyebut perintah-perintah level rendah ini plumbing (pipa saluran) dan perintah ramah pengguna sebagai porcelain (keramik halus di atasnya) — pembagian yang berasal dari desain asli Git, dijelaskan pada bab Git Internals
Pro Git. Ketika porcelain macet, plumbing selalu tersedia sebagai jalan manual — kita akan memakainya nyata untuk menulis blob tanpa git add.
Empat jenis objek sudah dikenali; yang belum kita lakukan adalah membuka masing-masing dan membaca isinya baris demi baris. Chapter berikutnya, Blob, Tree, Commit, dan Tag , membedah keempatnya sampai ke byte terakhir.