Sepanjang section ini kita mengisi kotak peralatan untuk membaca riwayat: format dan filter git log, pickaxe, blame, shortlog, sampai relasi parent. Semua alat itu bernilai penuh hanya pada satu syarat — riwayat yang dibacanya layak dibaca. Riwayat bukan laik-otomatis: kualitasnya ditentukan pada saat setiap commit dibuat, bukan saat dibutuhkan. Chapter penutup ini membandingkan dua repository dengan isi akhir yang persis sama namun nasib berbeda, lalu merangkum kebiasaan yang membedakan keduanya — kebiasaan yang membuat seluruh alat section ini bekerja cepat enam bulan kemudian.
Dua Repository dengan Isi yang Sama #
Repository pertama dikerjakan buru-buru: checkpoint disimpan kapan pun kepala kosong, pesan ditulis seadanya. Lima commit menghasilkan aplikasi diskon yang jalan:
mkdir latihan-berantakan && cd latihan-berantakan
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf '# Aplikasi Diskon\nHitung potongan harga.\n' > README.md
printf 'def hitung_diskon(total):\n return total * 0.1\n' > diskon.py
git add README.md diskon.py
git commit -m "wip"
printf 'def hitung_diskon(total):\n potongan = 0.1\n print("hitung diskon", total)\n return total - (total * potongan)\n' > diskon.py
git add diskon.py
git commit -m "wip"
printf '# Aplikasi Diskon\n\nHitung potongan harga.\n' > README.md
git add README.md
git commit -m "fix"
printf 'def ekspor(nama, hasil):\n with open(nama, "w") as berkas:\n berkas.write(str(hasil))\n' > ekspor.py
printf '# Aplikasi Diskon\n\nHitung potongan harga keranjang belanja.\n' > README.md
git add ekspor.py README.md
git commit -m "update"
printf 'def hitung_diskon(total):\n potongan = 0.1\n return total - (total * potongan)\n' > diskon.py
git add diskon.py
git commit -m "beres"Riwayatnya:
git log --onelineOutput yang Dihasilkan:
8eb6e56 beres
3f27847 update
94f5e57 fix
cb7dbe5 wip
6e3d9f8 wipRepository kedua menempuh perubahan yang sama — berkas, isi, dan urutan logisnya identik — tanpa pernah menyimpan baris debug maupun pesan generik. Setiap commit menghentikan pekerjaan pada satu titik yang bermakna:
cd .. && mkdir latihan-rapi && cd latihan-rapi
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf '# Aplikasi Diskon\nHitung potongan harga.\n' > README.md
printf 'def hitung_diskon(total):\n return total * 0.1\n' > diskon.py
git add README.md diskon.py
git commit -m "Tambah kerangka aplikasi diskon"
printf 'def ekspor(nama, hasil):\n with open(nama, "w") as berkas:\n berkas.write(str(hasil))\n' > ekspor.py
git add ekspor.py
git commit -m "Tambah ekspor hasil ke berkas"
printf 'def hitung_diskon(total):\n potongan = 0.1\n return total - (total * potongan)\n' > diskon.py
git add diskon.py
git commit -m "Gunakan variabel potongan pada rumus diskon"
printf '# Aplikasi Diskon\n\nHitung potongan harga keranjang belanja.\n' > README.md
git add README.md
git commit -m "Perjelas deskripsi aplikasi di README"git log --onelineOutput yang Dihasilkan:
88f2ee2 Perjelas deskripsi aplikasi di README
ae25804 Gunakan variabel potongan pada rumus diskon
1c347da Tambah ekspor hasil ke berkas
01c559b Tambah kerangka aplikasi diskonRiwayat yang Tak Bisa Dicari #
Kedua daftar di atas sama-sama menampilkan aplikasi jadi — bedanya baru terasa saat riwayat digunakan. Dua pekan kemudian, tim menanyakan: “fitur ekspor itu kapan masuk?”. Filter --grep dari chapter Opsi git log
mencarinya di dalam pesan commit:
git log --grep="ekspor" --onelineOutput yang Dihasilkan:
Keluaran kosong — tidak satu pun pesan di latihan-berantakan menyebut ekspor. Yang menambahkan berkas ekspor.py adalah commit update, dan tak ada manusia yang bisa menebaknya dari kelima pesan itu. Pencarian yang sama pada repository kedua:
git log --grep="ekspor" --onelineOutput yang Dihasilkan:
1c347da Tambah ekspor hasil ke berkasSatu baris, langsung kena. Inilah hakikat riwayat sehat sebagai navigasi: filter pesan, pickaxe -S, dan blame dari chapter Mencari Commit
serta git blame
semuanya bergantung pada pesan yang menggambarkan isi. Pickaxe memang tetap menemukan 3f27847 di repository pertama — teks ekspor ada di dalam diff — namun commit yang ditemukannya menyandang pesan update: penemuan tanpa penjelasan.
Commit Atomik: Satu Maksud per Commit #
Isi commit update di repository pertama:
git show --stat 3f27847Output yang Dihasilkan:
commit 3f278478fb9797a0142442748e0747d8410b330c
Author: Budi Santoso <[email protected]>
Date: Tue Oct 13 09:30:00 2026 +0700
update
README.md | 2 +-
ekspor.py | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)Satu commit memuat dua maksud sekaligus: fitur baru (ekspor.py) dan suntingan dokumentasi (README.md). Campuran begini terasa jinak saat dibuat, lalu berubah jadi beban: fitur ekspor tidak bisa di-revert atau di-cherry-pick tanpa menyeret suntingan README ikut serta, dan peninjau harus memahami dua topik dalam satu bacaan. Padanannya di repository kedua:
git show --stat 1c347daOutput yang Dihasilkan:
commit 1c347daa5e884ae8a4ec750b9778d595dfa4c7ad
Author: Budi Santoso <[email protected]>
Date: Tue Oct 13 09:05:00 2026 +0700
Tambah ekspor hasil ke berkas
ekspor.py | 3 +++
1 file changed, 3 insertions(+)Satu berkas, satu maksud, satu pesan yang menyebut keduanya. Aturan commit atomik berbunyi persis begitu: satu commit menampung satu perubahan yang utuh dan bernama jelas. Ukurannya mengikuti maksudnya, bukan jumlah baris — fitur kecil cukup satu commit, fitur besar menjadi rangkaian commit atomik (kerangka, lalu perilaku, lalu perapihan), dan pekerjaan yang tidak berhubungan — misalnya refactor tata letak — tidak pernah naik satu kendaraan dengan fitur.
Isi Akhir Sama, Pohon yang Sama #
Puncak pembuktian: apakah kedisiplinan itu mengubah hasil akhir? Kita bandingkan objek tree pada puncak masing-masing repository — snapshot seluruh isi direktori yang dibekukan tiap commit:
git rev-parse HEAD^{tree}Output yang Dihasilkan (di latihan-berantakan):
17383cc54bb7a1876e840b92f9c60b522473f1edgit rev-parse HEAD^{tree}Output yang Dihasilkan (di latihan-rapi):
17383cc54bb7a1876e840b92f9c60b522473f1edHash identik — byte demi byte. Kedua repository berakhir pada isi yang persis sama karena tree dihitung dari isi, bukan dari cara mencapainya. Git sendiri tidak menilai riwayat mana yang lebih sehat; mesin menilai objek, manusia menilai jejak. Keputusan “bagaimana kita melangkah” hanya berdampak pada satu hal — keterbacaan riwayat — dan itu satu-satunya hal yang dibaca enam bulan kemudian.
Checkpoint Pribadi: wip dan Squash #
Commit wip tetap punya tempat yang sah: sebagai checkpoint pribadi selagi bekerja. Kepala memang perlu dikosongkan di tengah fitur besar, dan checkpoint lokal mencegah pekerjaan hilang. Aturannya satu kalimat: checkpoint boleh hidup hanya di branch privat, dan harus disatukan sebelum pekerjaan dibagikan. Proses menyatukannya — memeras lima commit wip menjadi tiga commit bermakna — dikerjakan lewat interactive rebase dengan aksi squash, dibahas tuntas di section Rebasing dan Riwayat Lanjutan
, khususnya chapter Interactive Rebase
dan Menggabungkan Commit
. Untuk koreksi kecil pada commit terakhir yang belum dibagikan, --amend dari chapter Amend Commit
sudah cukup.
Prinsipnya: riwayat bersama adalah produk publik tim; riwayat privat adalah papan draf. Keduanya dipisahkan oleh satu operasi squash sebelum push — bukan oleh keberanian menghapus jejak setelah orang lain melihatnya. Panduan menyumbang pada proyek terbuka umumnya menuntut hal yang sama, misalnya bab berkontribusi Pro Git di git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project .
Lakukan dan Hindari #
| Lakukan | Hindari |
|---|---|
| Satu maksud per commit; fitur besar menjadi rangkaian commit atomik | Mencampur fitur, refactor, dan dokumentasi dalam satu commit |
| Subjek imperatif yang menyebut isi; body menjelaskan alasan | Pesan generik: wip, update, fix, beres |
Periksa git diff --staged sebelum commit | git add -A asal cepat tanpa membaca apa yang masuk |
| Commit ketika repository dalam keadaan benar dan bisa jalan | Menyimpan keadaan setengah-jadi ke branch bersama |
Checkpoint wip hanya di branch privat, squash sebelum dibagikan | Push commit wip ke branch yang dipakai bersama |
| Format pesan yang konsisten di tim, mis. Conventional Commits | Menyalin isi diff ke body pesan — diff sudah ada |
Kebiasaan dari Section Ini #
Rangkaian kebiasaan kecil di atas punya satu efek besar yang terasa setiap hari: navigasi menjadi cepat. --grep menemukan commit lewat pesannya karena pesan menggambarkan isi; pickaxe -S menemukan kelahiran dan kematian sebuah teks karena perubahan tidak tercampur; git blame menunjuk penulis yang relevan karena format ulang tidak membajak atribusi; shortlog menyusun laporan yang bisa dibaca tanpa interpretasi. Riwayat sehat bukan kosmetik — ia adalah indeks yang kita bangun satu commit demi satu commit, dan seluruh section ini adalah mesin pencarinya.
Dengan commit yang tertata dan riwayat yang bisa dibaca, satu pertanyaan muncul begitu tim bertambah besar: bagaimana banyak orang mengerjakan banyak hal bersamaan tanpa saling menabrak? Jawabannya membuat riwayat bercabang — dan itulah pintu masuk section berikutnya: Branch dan Merging .