Database objek Git kini terbuka: blob, tree, commit, dan tag yang saling menunjuk lewat alamat hasil perhitungan isi. Tapi alamat seperti bd460ab5... mustahil dihafal manusia — kita bekerja dengan nama: main, v1.0.0, origin/main. Lapisan penerjemah nama-ke-alamat bernama refs (references), dan bab ini membongkarnya sampai ke berkasnya: branch ternyata berkas teks 41 byte, remote tracking branch tinggal di folder sendiri, dan riwayat pergerakan tiap penunjuk tercatat di reflog. Kita juga menyaksikan ratusan refs diringkas menjadi satu berkas packed-refs oleh git gc.

Refs Adalah Berkas Berisi Satu Hash #

Chapter Konsep Branch sudah membocorkan bahwa branch adalah penunjuk; kini kita telusuri seluruh keluarganya. Bangun repository latihan dengan tiga commit, branch bersarang, dua jenis tag, dan satu remote lokal:

bash
mkdir latihan-refs && cd latihan-refs
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf 'Keranjang:\n- kopi\n' > keranjang.md
git add keranjang.md
git commit -m "Buat keranjang belanja"
printf 'Keranjang:\n- kopi\n- gula\n' > keranjang.md
git add keranjang.md
git commit -m "Tambah gula"
git tag v0.9.0
printf 'Keranjang:\n- kopi\n- gula\n- teh\n' > keranjang.md
git add keranjang.md
git commit -m "Tambah teh"
git branch fitur/opsi-gelap HEAD~1
git tag -a v1.0.0 -m "Rilis pertama"
git init --bare ../latihan-refs-origin.git
git remote add origin ../latihan-refs-origin.git
git push origin main

Seluruh penunjuk hidup di bawah folder .git/refs:

bash
ls -R .git/refs/heads .git/refs/tags .git/refs/remotes

Output yang Dihasilkan:

text
.git/refs/heads:
fitur
main

.git/refs/heads/fitur:
opsi-gelap

.git/refs/remotes:
origin

.git/refs/remotes/origin:
main

.git/refs/tags:
v0.9.0
v1.0.0

Peta lengkapnya terlihat dari nama jalurnya: dua branch lokal (satu di folder bersarang fitur/), satu branch pelacak remote, dan dua tag. Isi berkas-berkas itu kita baca semua sekaligus:

bash
for f in .git/refs/heads/main .git/refs/heads/fitur/opsi-gelap .git/refs/tags/v0.9.0 .git/refs/tags/v1.0.0 .git/refs/remotes/origin/main; do echo "--- $f"; cat "$f"; done

Output yang Dihasilkan:

text
--- .git/refs/heads/main
bd460ab5fa50718df5a58b3cacb77fc48726c426
--- .git/refs/heads/fitur/opsi-gelap
727986b34a40d16d73b0991e5facb9534926d029
--- .git/refs/tags/v0.9.0
727986b34a40d16d73b0991e5facb9534926d029
--- .git/refs/tags/v1.0.0
4745b1e9824dac02120dd6202098e880d8a71b21
--- .git/refs/remotes/origin/main
bd460ab5fa50718df5a58b3cacb77fc48726c426

Lima berkas, lima hash — dan tiap hash punya cerita. main menunjuk commit “Tambah teh”; fitur/opsi-gelap dan tag ringan v0.9.0 sama-sama menunjuk commit “Tambah gula” (branch dibuat di HEAD~1, tag ditempel setelah commit itu); origin/main menunjuk commit yang sama dengan main karena barusan kita push. Tag v1.0.0 adalah satu-satunya yang beda isi: hash 4745b1e... adalah objek tag dari chapter Blob, Tree, Commit, dan Tag — annotated tag menunjuk objek tag, objek tag yang menunjuk commit.

Peta posisi semua penunjuk bisa dicek dari satu perintah:

bash
git log --oneline --all --decorate

Output yang Dihasilkan:

text
bd460ab (HEAD -> main, tag: v1.0.0, origin/main) Tambah teh
727986b (tag: v0.9.0, fitur/opsi-gelap) Tambah gula
7dece8b Buat keranjang belanja

Namespace dan Hierarki #

Struktur folder refs bukan kebetulan — Git membagi penunjuk berdasarkan namespace, dan garis miring membuat sub-folder sehingga nama bisa bersarang tanpa tabrakan (refs/heads/fitur/opsi-gelap dan refs/heads/fitur/kecepatan hidup berdampingan):

NamespaceMenunjuk keDibuat oleh
refs/heads/Branch lokal (commit)git branch, git commit
refs/tags/Tag ringan (commit) atau annotated (objek tag)git tag
refs/remotes/Salinan branch remote hasil fetch/pushgit fetch, git push
HEADBukan folder — berkas istimewa posisi kita sekaranggit switch

refs/remotes/origin/main adalah remote-tracking branch yang bekerja persis seperti dijelaskan pada Remote-Tracking Branch : potret posisi branch main di server origin saat terakhir dihubungi. Namespace lain juga ada — refs/stash untuk simpanan sementara, refs/notes/ untuk anotasi — semuanya mengikuti pola yang sama: nama di folder, hash di dalam.

rev-parse: Penerjemah Semua Bentuk Nama #

Perintah git rev-parse adalah penerjemah resmi dari bentuk nama apa pun menjadi hash utuh. Tag annotated menyimpan kejutan kecil:

bash
git rev-parse v1.0.0

Output yang Dihasilkan:

text
4745b1e9824dac02120dd6202098e880d8a71b21
bash
git rev-parse v1.0.0^{commit}

Output yang Dihasilkan:

text
bd460ab5fa50718df5a58b3cacb77fc48726c426

Nama v1.0.0 diselesaikan ke objek tag, bukan commit — akhiran ^{commit} mengupasnya sampai ke commit yang ditunjuk. Bentuk-bentuk lain dari repository yang sama:

BentukDiselesaikan menjadiHasil
mainIsi refs/heads/mainbd460ab...
v1.0.0Objek tag4745b1e...
v1.0.0^{commit}Commit di balik tagbd460ab...
main~1Parent dari main727986b...
HEADDiselesaikan lewat berkas HEADbd460ab...

Mekanisme resolusi inilah yang bekerja diam-diam setiap kali kita mengetik git show main, git diff main~1, atau git log v1.0.0 — Git menerjemahkan dulu, baru membuka objeknya. Nama pendek seperti main atau v1.0.0 sebenarnya disingkat: aturan urutannya Git mencari main di refs/tags, refs/heads, lalu hash singkat — bab Git References Pro Git merinci urutan lengkapnya.

Reflog: Riwayat Pergerakan Tiap Ref #

Refs bergerak terus — commit menggeser main, switch memindahkan HEAD — dan Git mencatat setiap pergerakan itu di reflog. Foldernya bisa kita lihat strukturnya:

bash
ls -R .git/logs

Output yang Dihasilkan:

text
.git/logs:
HEAD
refs

.git/logs/refs:
heads
remotes

.git/logs/refs/heads:
fitur
main

.git/logs/refs/heads/fitur:
opsi-gelap

.git/logs/refs/remotes:
origin

.git/logs/refs/remotes/origin:
main

Struktur .git/logs mencerminkan .git/refs: tiap ref yang pernah bergerak punya berkas log sendiri. Isi .git/logs/HEAD kita bedah baris per baris:

bash
cat .git/logs/HEAD

Output yang Dihasilkan:

text
0000000000000000000000000000000000000000 7dece8ba93661ee80d764daedd1fa41464395b2c Budi Santoso <[email protected]> 1793934000 +0700	commit (initial): Buat keranjang belanja
7dece8ba93661ee80d764daedd1fa41464395b2c 727986b34a40d16d73b0991e5facb9534926d029 Budi Santoso <[email protected]> 1793934300 +0700	commit: Tambah gula
727986b34a40d16d73b0991e5facb9534926d029 bd460ab5fa50718df5a58b3cacb77fc48726c426 Budi Santoso <[email protected]> 1793934600 +0700	commit: Tambah teh

Tiap baris memuat lima potong informasi: posisi lama, posisi baru, identitas pelaku, stempel waktu, lalu aksi dan pesannya (dipisahkan tab dari stempel waktu). Baris pertama mencatat HEAD bergerak dari hash nol — commit pertama belum punya posisi sebelumnya. Reflog inilah jaring pengaman di balik git reflog dan seluruh pemulihan commit “hilang” pada Git Reflog — objek yang sudah tak ditunjuk refs mana pun tetap bisa ditemukan lewat catatan ini. Tampilan ringkasnya:

bash
git reflog

Output yang Dihasilkan:

text
bd460ab HEAD@{0}: commit: Tambah teh
727986b HEAD@{1}: commit: Tambah gula
7dece8b HEAD@{2}: commit (initial): Buat keranjang belanja

packed-refs: Ratusan Penunjuk, Satu Berkas #

Kelemahan refs lepas muncul di repository besar: satu berkas per ref berarti ribuan berkas kecil — tiap pembacaan refs menjadi satu operasi sistem berkas. git gc merapikannya dengan mengemas seluruh refs ke satu berkas terurut:

bash
git gc -q
ls -R .git/refs

Output yang Dihasilkan:

text
.git/refs:
heads
remotes
tags

.git/refs/heads:
fitur

.git/refs/heads/fitur:

.git/refs/remotes:
origin

.git/refs/remotes/origin:

.git/refs/tags:

Folder-folernya masih ada tapi kosong — berkas main sudah tidak ada:

bash
cat .git/refs/heads/main

Output yang Dihasilkan:

text
cat: .git/refs/heads/main: No such file or directory

Seluruh isi pindah ke .git/packed-refs:

bash
cat .git/packed-refs

Output yang Dihasilkan:

text
# pack-refs with: peeled fully-peeled sorted 
727986b34a40d16d73b0991e5facb9534926d029 refs/heads/fitur/opsi-gelap
bd460ab5fa50718df5a58b3cacb77fc48726c426 refs/heads/main
bd460ab5fa50718df5a58b3cacb77fc48726c426 refs/remotes/origin/main
727986b34a40d16d73b0991e5facb9534926d029 refs/tags/v0.9.0
4745b1e9824dac02120dd6202098e880d8a71b21 refs/tags/v1.0.0
^bd460ab5fa50718df5a58b3cacb77fc48726c426

Baris pertama berjudul # pack-refs with: peeled fully-peeled sorted — tiga sifat berkas ini. Setiap baris berikut memasangkan hash dan nama ref dalam satu spasi, terurut agar pencarian cepat. Baris berawalan ^ adalah hasil peeled: objek tag v1.0.0 dikupas menjadi commit yang ditunjuknya bd460ab..., disimpan sebagai jawaban siap pakai sehingga Git tak perlu membuka objek tag setiap kali tag ini diperlukan. Kemasan ini transparan total:

bash
git rev-parse main

Output yang Dihasilkan:

text
bd460ab5fa50718df5a58b3cacb77fc48726c426
bash
git symbolic-ref HEAD

Output yang Dihasilkan:

text
refs/heads/main

git rev-parse main tetap menemukan bd460ab... — kini dari packed-refs — dan git symbolic-ref HEAD tetap membaca berkas HEAD yang memang tidak ikut dikemas. Refs lepas dan terkemas hidup berdampingan: ref yang bergerak ditulis ulang sebagai berkas lepas, lalu dikemas lagi pada git gc berikutnya.

Di antara semua penunjuk ini, satu berkas istimewa menempati posisi teratas: HEAD — penunjuk yang menjawab “kita sedang berada di mana”. Berkas itu terkadang berisi ref: refs/heads/main, terkadang berisi hash telanjang — dua wajah yang menentukan apakah pekerjaan kita aman atau terancam. Chapter berikutnya, HEAD dan Detached HEAD , membedah kedua wajahnya.