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 ← pointer ke branch aktif
objects/ ← semua object tersimpan di sini
refs/
heads/ ← pointer branch lokal (main, fitur-x)
remotes/ ← pointer branch remote (origin/main)
tags/ ← pointer tag
config ← konfigurasi repo
index ← staging area
4 jenis object Git:
| Object | Isi | Analogi |
|---|---|---|
| blob | konten file (tanpa nama) | isi buku |
| tree | daftar nama file + permission + hash blob/tree | daftar isi folder |
| commit | pointer ke tree + parent + author + pesan | snapshot berlabel |
| tag | pointer ke commit + metadata (annotated tag) | bookmark resmi |
Setiap object diidentifikasi dengan SHA-1 hash 40 karakter dari isinya. Sama isi → sama hash → tidak ada duplikasi.
Commit bukanlah "diff" — commit adalah snapshot:
commit abc123
├── tree def456 (snapshot seluruh folder)
│ ├── blob 111 index.html
│ ├── blob 222 style.css
│ └── tree ghi789 src/
│ └── blob 333 app.js
├── parent xyz987 (commit sebelumnya)
└── pesan: "tambah fitur login"
Ref: branch adalah pointer, bukan "benda":
$ cat .git/refs/heads/main
abc123... ← hanya 40 karakter SHA, itu saja!
Ketika kamu commit, Git membuat object commit baru dan memindahkan pointer refs/heads/main ke hash baru. Itu sebabnya branching di Git sangat murah.
HEAD:
$ cat .git/HEAD
ref: refs/heads/main ← HEAD menunjuk ke branch
Saat git checkout abc123 (detached HEAD), isinya jadi SHA langsung, bukan ref.
Commit DAG (Directed Acyclic Graph):
Commit menunjuk ke parent-nya (bukan child). Merge commit punya 2+ parent. Tidak ada siklus — maka "Acyclic".
Eksperimen: jalankan
git cat-file -p <hash>untuk melihat isi object, dangit rev-parse HEADuntuk hash commit terakhir.