Kita sudah membuka isi database objek, refs, dan HEAD — tetapi satu berkas masih bekerja diam-diam setiap kali kita menjalankan git add dan git status: .git/index. Inilah mesin di balik staging area yang sejak section Melacak Perubahan
kita pakai sebagai konsep. Chapter ini membedahnya secara mekanis — membaca entrinya lewat ls-files -s, membuktikan staging adalah satu berkas biner (bukan objek), menjalankan alur add lewat plumbing, lalu menyaksikan konflik merge membelah index menjadi tiga panggung.
Index: Snapshot Staging dalam Satu Berkas #
Repository latihan kita mulai sederhana — satu berkas, satu commit:
mkdir latihan-index && cd latihan-index
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf 'espresso 18000\n' > menu.txt
git add menu.txt
git commit -m "Buat daftar menu"Daftar isi index terbaca dengan plumbing git ls-files -s (staged):
git ls-files -sOutput yang Dihasilkan:
100644 d433484e4c05ef2efa746269a28947b95c83b103 0 menu.txtSatu entri dengan empat kolom: mode berkas, hash blob, nomor stage (angka 0 — arti pentingnya segera kita lihat), lalu nama berkas (dipisahkan tab). Inilah seluruh isi staging area: daftar “path → blob” yang akan menjadi isi commit berikutnya. Wujud fisiknya:
ls -l .git/indexOutput yang Dihasilkan:
-rw-rw-r-- 1 z z 137 Oct 13 15:16 .git/indexfile .git/indexOutput yang Dihasilkan:
.git/index: Git index, version 2, 1 entriesIndex bukan objek di objects/ — tidak dialamatkan hash, tidak immutable, tidak masuk riwayat. Index hanyalah satu berkas biner biasa yang ditulis ulang setiap kali staging berubah. Saat commit dibuat, Git merangkai tree dari daftar ini — snapshot commit memang potret index saat itu, buktinya menyusul di bawah.
Alur add: Hitung Hash, Simpan Blob, Perbarui Index #
Mari kita bedah apa yang sebenarnya dikerjakan git add. Sunting harga tanpa mendaftarkannya:
printf 'espresso 20000\n' > menu.txt
git ls-files -sOutput yang Dihasilkan:
100644 d433484e4c05ef2efa746269a28947b95c83b103 0 menu.txtgit status --shortOutput yang Dihasilkan:
M menu.txtBerkas di disk sudah berubah, tetapi index masih mencatat blob lama d433484... — itulah mengapa status melaporkan M. Hash isi yang baru bisa dihitung tanpa menyentuh staging:
git hash-object menu.txtOutput yang Dihasilkan:
e29201c2a49faafed39ff5bbacba04e5f19a7e94git count-objectsOutput yang Dihasilkan:
3 objects, 12 kilobytesPerhatikan: hash e29201c... sudah diketahui, tapi database masih berisi 3 objek (commit, tree, blob lama) — hash-object tadi hanya menghitung, belum menyimpan. Sekarang daftarkan:
git add menu.txt
git ls-files -sOutput yang Dihasilkan:
100644 e29201c2a49faafed39ff5bbacba04e5f19a7e94 0 menu.txtgit count-objectsOutput yang Dihasilkan:
4 objects, 16 kilobytesTiga hal terjadi dalam satu git add: blob baru disimpan (3 → 4 objek), entri menu.txt di index digeser ke hash baru, dan selesai — tidak ada commit, tidak ada tree baru. Staging hanyalah pembaruan satu baris daftar.
update-index –add: Staging Tanpa git add #
Kalau add cuma itu pekerjaannya, kita seharusnya bisa mengerjakannya manual dengan plumbing. Benar — git update-index --add mendaftarkan berkas ke index tanpa git add:
printf 'Pelanggan:\n- Siti\n' > pelanggan.txt
git update-index --add pelanggan.txt
git status --shortOutput yang Dihasilkan:
M menu.txt
A pelanggan.txtPerintah update-index --add sunyi, tapi statusnya nyata: A (added) pada pelanggan.txt — berkas baru itu kini staged tanpa pernah disentuh git add. Blob-nya juga tersimpan, seperti terlihat dari jumlah objek:
git count-objectsOutput yang Dihasilkan:
5 objects, 20 kilobytesgit ls-files -sOutput yang Dihasilkan:
100644 e29201c2a49faafed39ff5bbacba04e5f19a7e94 0 menu.txt
100644 70c8d3b5dae8af7e68ba3bb4c440ac52e353aefa 0 pelanggan.txtPorcelain git add, plumbing update-index --add — hasil akhirnya identik. Bedah penuh daftar perintah plumbing dan porcelain dibuka pada chapter Object Model
.
write-tree: Index Menjadi Snapshot #
git write-tree merangkai tree dari isi index saat ini — langkah yang oleh git commit dikerjakan diam-diam:
git write-treeOutput yang Dihasilkan:
0a36a11b5daf460d0167e64b18ae61d1304e540cTree itu tersimpan di database — dan commit yang kita buat sesudahnya memakai tree yang sama persis:
git commit -m "Naikkan harga espresso dan daftar pelanggan"
git cat-file -p HEADOutput yang Dihasilkan:
tree 0a36a11b5daf460d0167e64b18ae61d1304e540c
parent 303205ab0bf31e63ac6e7691752eee2ce476a3c0
author Budi Santoso <[email protected]> 1794021300 +0700
committer Budi Santoso <[email protected]> 1794021300 +0700
Naikkan harga espresso dan daftar pelangganBaris tree 0a36a11... pada commit identik dengan keluaran write-tree — commit memotret index, bukan working directory. Inilah alasan staging area disebut snapshot yang akan di-commit: yang masuk commit hanya yang terdaftar di index saat itu.
Index sebagai Cache: ctime dan mtime #
Nama lain index — cache — berasal dari perannya mempercepat status. Tiap entri index menyimpan statistik berkas:
git ls-files --debugOutput yang Dihasilkan:
menu.txt
ctime: 1791904612:407060083
mtime: 1791904612:407060083
dev: 44 ino: 152653
uid: 1001 gid: 1001
size: 15 flags: 0Selain hash blob, index menyimpan ctime (waktu metadata berubah), mtime (waktu isi berubah), nomor perangkat dan inode, ukuran, serta pemiliknya — nilai-nilai ini mengikuti berkas di mesin masing-masing. Fungsinya: git status membandingkan statistik itu dengan keadaan berkas di disk. Bila mtime dan size tidak berubah sejak terakhir dicatat, Git langsung menyimpulkan berkas tidak berubah tanpa membaca isi dan meng-hash-nya ulang; hanya berkas yang statistiknya bergeser yang diperiksa isinya. Di repository berisi puluhan ribu berkas, cache inilah yang membuat git status selesai dalam hitungan milidetik.
Konflik di Index: Stage 1, 2, 3 #
Angka 0 pada kolom ketiga ls-files -s akhirnya menemui maknanya. Kita ciptakan konflik: dua branch menyunting baris yang sama.
git switch -c fitur-harga
printf 'espresso 25000\n' > menu.txt
git add menu.txt
git commit -m "Naikkan harga jadi 25000"
git switch main
printf 'espresso 22000\n' > menu.txt
git add menu.txt
git commit -m "Naikkan harga jadi 22000"
git merge fitur-hargaOutput yang Dihasilkan:
Auto-merging menu.txt
CONFLICT (content): Merge conflict in menu.txt
Automatic merge failed; fix conflicts and then commit the result.Merge berhenti di tengah jalan — dan keadaan berhentinya terbaca langsung dari index:
git ls-files -sOutput yang Dihasilkan:
100644 e29201c2a49faafed39ff5bbacba04e5f19a7e94 1 menu.txt
100644 5144563a92a93ffbaf49fed013acf85f56457fbd 2 menu.txt
100644 0c0927312991510e4fab103de1a0456e5d87c3ea 3 menu.txt
100644 70c8d3b5dae8af7e68ba3bb4c440ac52e353aefa 0 pelanggan.txtmenu.txt kini menempati tiga panggung sekaligus: stage 1 versi bersama terakhir (e29201c... — harga 20000 sebelum kedua cabang menyimpang), stage 2 versi kita di main (5144563... — 22000), stage 3 versi fitur-harga (0c09273... — 25000). Tiga blob itulah sumber tanda <<<<<<</>>>>>>> di berkas konflik; pelanggan.txt yang tak terlibat tetap tenang di stage 0. Status singkatnya terkenal:
git status --shortOutput yang Dihasilkan:
UU menu.txtUU berarti kedua sisi menyunting — penanda yang dibahas penuh di Menyelesaikan Merge Conflicts
. Penyelesaiannya pun berujung di index: pilih isi akhir, lalu git add menu.txt menutup tiga panggung menjadi satu:
printf 'espresso 22000\nkopi susu 25000\n' > menu.txt
git add menu.txt
git ls-files -sOutput yang Dihasilkan:
100644 d707de7d592117c735e5ecac91632800503fc6f2 0 menu.txt
100644 70c8d3b5dae8af7e68ba3bb4c440ac52e353aefa 0 pelanggan.txtBlob baru d707de7... (hasil penggabungan) duduk di stage 0 — index kembali normal, dan commit merge tinggal menulis tree dari daftar itu.
Rename: Kesimpulan Index, Bukan Data yang Disimpan #
Penutup yang menghubungkan index dengan satu fakta lama: Git tidak menyimpan kata “rename” di objeknya. Uji cepat:
git commit -m "Selesaikan konflik harga menu"
git mv menu.txt daftar-menu.txt
git status --shortOutput yang Dihasilkan:
R menu.txt -> daftar-menu.txtgit diff --cached -M --summaryOutput yang Dihasilkan:
rename menu.txt => daftar-menu.txt (100%)git mv mengerjakan dua operasi yang kini kita kenali: memindahkan berkas di disk dan memperbarui index (buang entri menu.txt, daftarkan daftar-menu.txt menunjuk blob yang sama). Label R dan baris rename ... (100%) adalah kesimpulan yang dihitung ulang saat ditampilkan — index kehilangan satu path dan mendapat path lain dengan blob identik — bukan data yang tersimpan. Parameter -M mengaktifkan deteksinya; mekanisme lengkapnya dibedah di git mv
.
Empat mekanisme Git kini utuh kita pegang: objek menyimpan isi, refs memberi nama, HEAD mencatat posisi, index menjembatani disk dengan commit. Satu pertanyaan dari awal section masih menggantung: mengapa repository tidak membengkak meski menyimpan setiap versi tiap berkas sebagai objek lepas? Jawabannya di teknik pengemasan di .git/objects/pack — packfile dan kompresi delta-nya, pembuka part berikutnya: Packfiles
.