Alur Kerja Harian
Stage, Commit, History
Inti pekerjaan sehari-hari dengan Git adalah satu loop kecil yang berulang: pilih perubahan dengan sadar, bungkus jadi commit yang baik, lalu baca kembali jejaknya saat dibutuhkan.
Di Chapter 1 kita paham Git menyimpan snapshot lewat tiga area. Chapter ini mengubah pemahaman itu menjadi kebiasaan harian yang berputar mulus: tracking untuk memilih apa yang masuk, commit untuk membungkusnya jadi catatan yang bermakna, dan history untuk membacanya kembali. Ketiganya satu lingkaran, makin rapi kamu memilih dan menulis, makin berharga history yang bisa kamu baca berbulan-bulan kemudian.
Tracking Perubahan
status, add, restore, diff: memilih perubahan dengan sadar
Git memisahkan perubahan menjadi tiga kondisi, dan justru di pemisahan itulah letak kendali kamu atas apa yang masuk ke sebuah commit.
Sebuah file yang kamu sentuh hidup di salah satu dari tiga kondisi: modified (sudah diubah di working tree tapi belum ditandai), staged (sudah dipilih ke staging area, siap dibungkus jadi commit), dan committed (sudah tersimpan permanen di repository). Staging area inilah yang sering diremehkan pemula: ia bukan sekadar formalitas sebelum commit, melainkan ruang untuk menyusun commit secara sadar, memilih perubahan mana yang layak masuk bersama dan mana yang ditunda.
Titik masuknya selalu git status. Perintah ini membaca ketiga area dan memberitahu kamu: file mana yang modified tapi belum staged, file mana yang sudah staged, dan file mana yang sama sekali belum dilacak (untracked). Biasakan menjalankannya sebelum dan sesudah git add, karena ia adalah kompasmu, bukan sekadar laporan.
Terminal$ git status On branch main Changes to be committed: (use "git restore --staged <file>..." to unstage) modified: internal/product/handler.go Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: internal/product/service.go
Untuk memindahkan perubahan ke staging, git add <path>. Untuk membatalkan, ada dua arah yang sering tertukar. git restore <file> membuang perubahan di working tree (mengembalikan file ke kondisi terakhir di index, perubahanmu hilang). Sementara git restore --staged <file> hanya meng-unstage: perubahan tetap ada di working tree, hanya dikeluarkan dari staging. Perhatikan perbedaannya: yang satu membuang isi, yang satu hanya menarik dari antrean commit.
git restore service.go menimpa file dengan versi index dan tidak masuk reflog, jadi perubahan working tree yang belum di-commit benar-benar lenyap. Pastikan kamu memang ingin membuangnya.
Dua perintah diff menjawab dua pertanyaan berbeda. git diff menunjukkan selisih working tree vs index: perubahan yang sudah kamu buat tapi belum di-stage. git diff --staged menunjukkan index vs HEAD: persis apa yang akan tercatat bila kamu commit sekarang. Membaca keduanya sebelum commit adalah kebiasaan yang memisahkan commit rapi dari commit berantakan.
Sama seperti kamu memindai diff di tab Source Control sebelum stage, git diff dan git diff —staged adalah versi terminal yang portabel, bisa di-pipe, dan tidak bergantung pada editor mana pun.
Mari praktik. Ubah dua file, stage satu, lalu bandingkan kedua diff sebelum commit.
Terminal$ git add internal/product/handler.go # stage satu file saja $ git diff # sisa yang BELUM di-stage (service.go) $ git diff --staged # yang AKAN masuk commit (handler.go) $ git commit -m "Validate price is positive in product handler"
Di dunia nyata, kemampuan memilih potongan inilah yang menyelamatkan history. Bayangkan kamu sedang memperbaiki validasi harga, tapi di tengah jalan iseng merapikan nama variabel di fungsi yang sama. Dua hal itu tidak berhubungan, dan menggabungnya jadi satu commit membuat keduanya sulit dipisah nanti. git add -p menyelesaikan ini: ia menampilkan tiap hunk dan bertanya y/n, sehingga satu file berisi dua perubahan bisa dipecah jadi dua commit terpisah.
- Menyapu semua perubahan tanpa kamu lihat.
- Perbaikan bug dan rename tak relevan tercampur di satu commit.
- Rentan ikut menstage file rahasia atau setengah jadi.
- Menapis per hunk, kamu memutuskan tiap potongan.
- Tiap commit tetap atomic, satu ide per commit.
- Diff sempat kamu baca ulang sebelum masuk staging.
Commit yang Baik
Atomic, pesan jelas, why over what
Commit yang baik bukan tentang menyimpan kode, melainkan menulis catatan yang masih masuk akal saat dibaca enam bulan kemudian oleh orang yang lupa konteksnya, termasuk dirimu sendiri.
Prinsip pertama adalah atomic: satu commit memuat satu perubahan logis yang utuh. Bukan “satu file”, bukan “satu hari kerja”, tapi satu ide yang bisa dijelaskan dalam satu kalimat. Commit atomic membuat git log mudah dibaca, git revert aman (membatalkan satu commit tidak ikut menghapus hal lain), dan git bisect efektif saat memburu bug. Bila kamu menggabungkan perbaikan validasi harga dengan rename variabel di satu commit, dua-duanya jadi sulit dipisah lagi nanti. Inilah kenapa git add -p di section sebelumnya penting: ia alat untuk menjaga keatomikan.
Seperti memecah satu task besar di issue tracker jadi sub-task kecil yang jelas, satu perubahan logis sebaiknya menjadi satu commit terisolasi. Issue memberi batas; commit menjadi jejak teknis dari batas itu.
Prinsip kedua adalah pesan yang menjelaskan kenapa. Pesan commit punya dua bagian: subject (baris pertama) dan body (paragraf setelah baris kosong). Subject ditulis imperatif dan singkat, sekitar maksimal 50 karakter, seolah memberi perintah: “Add”, “Fix”, “Refactor”, bukan “Added” atau “Fixing”. Body, yang opsional, dibungkus sekitar 72 karakter per baris dan menjelaskan kenapa perubahan ini perlu, bukan mengulang apa yang sudah terbaca dari diff. Konvensi 50/72 ini bukan rewel gaya: subject pendek tampil utuh di git log --oneline, di daftar PR, dan di antarmuka hosting tanpa terpotong.
| Buruk | Baik | Kenapa |
|---|---|---|
update | Add price validation to product handler | Subjek buruk tak menjelaskan apa pun saat dibaca di log. |
fix bug | Fix negative PriceRupiah passing validation | ”Bug” yang mana? Subjek baik menyebut gejala spesifik. |
wip | Refactor product service to accept context | ”wip” tidak punya makna di history permanen. |
Pesan seperti wip, update, fix bug, atau asdf membuat history jadi kabut. Saat kamu menelusuri kenapa sebuah baris berubah, pesan kosong memaksamu membaca seluruh diff dari nol.
Berikut anatomi pesan commit yang lengkap: subject imperatif singkat, baris kosong, lalu body yang menjawab “kenapa”.
Pesan commitReject negative price at product creation PriceRupiah disimpan sebagai int64 dalam rupiah penuh, tapi handler lama menerima nilai negatif tanpa keluhan, lalu lolos sampai ke database. Validasi di tepi mencegah data harga rusak masuk ke sistem diskon yang mengandalkan nilai non-negatif.
Prinsip ketiga: pecah perubahan besar jadi beberapa commit logis. Bila satu sesi kerja menyentuh validasi, lalu rename, lalu perbaikan test, stage dan commit terpisah dengan bantuan git add -p agar tiap commit tetap atomic.
Terminal$ git add -p internal/product/service.go # pilih hunk validasi saja $ git commit -m "Reject negative price at product creation" $ git add -p internal/product/service.go # sekarang hunk rename $ git commit -m "Rename priceCents to priceRupiah for clarity"
Tulis subject seolah melengkapi kalimat “Commit ini akan …”: Add, Fix, Refactor. Simpan alasan dan trade-off di body, karena diff sudah menjawab “apa”, yang hilang justru “kenapa”.
Format pesan terstruktur ini punya kelanjutan yang kuat. Di Chapter 6 kita lihat bagaimana konvensi type(scope): description (Conventional Commits) membuat pesan bisa dibaca mesin untuk menghasilkan changelog dan menentukan versi rilis otomatis. Kebiasaan menulis subject imperatif yang jelas sekarang adalah modal untuk otomasi itu nanti.
Membaca History
log, show, diff tanpa rasa takut
History bukan museum yang hanya dipajang, melainkan alat investigasi: ia menjawab kenapa sebuah baris ada, kapan sebuah bug masuk, dan apa yang berubah di antara dua rilis.
Pintu utamanya git log. Apa adanya ia menampilkan tiap commit beserta hash, author, date, dan pesan, dari yang terbaru ke terlama. Tapi yang membuatnya berguna adalah flag-flagnya. --oneline memampatkan tiap commit jadi satu baris. --graph menggambar struktur cabang dengan garis ASCII. --all menyertakan semua branch, bukan hanya yang sedang aktif. Dikombinasikan, ketiganya memberi peta repositori yang cepat dibaca.
Terminal$ git log --oneline --graph --all * 8f3a1c2 (HEAD -> main) Reject negative price at product creation * a1b9d04 Add price validation to product handler | * 4c7e8f1 (feat/discount) Add discount engine skeleton |/ * 2d5a6b3 Initialize skincare-backend module layout
Peta cabang dari satu perintah. Garis menunjukkan feat/discount bercabang dari commit yang sama dengan main.
Secara model, history adalah rantai commit yang tiap simpulnya menunjuk ke induknya. Pada satu branch lurus, rantai itu terlihat seperti ini.
gitGraph commit id: "init module" commit id: "add handler" commit id: "validate price" commit id: "reject negative"
Rantai commit linear. Tiap commit menyimpan snapshot penuh dan menunjuk ke induknya, sehingga history bisa ditelusuri mundur.
Beberapa “lensa” history paling sering kamu pakai di kerja nyata, masing-masing menjawab satu pertanyaan investigasi yang berbeda.
git show <hash>
Lihat satu commit utuh: metadata plus diff lengkapnya. Pertanyaan: “apa persisnya yang commit ini ubah?“
git diff a..b
Selisih dari commit a ke b. Pertanyaan: “apa yang berubah sejak tag rilis terakhir?“
git log -p — path/file
Riwayat plus diff satu file. Pertanyaan: “bagaimana file ini berevolusi?“
git log —follow — file
Tetap menelusuri meski file pernah di-rename. Pertanyaan: “siapa dan kapan menyentuh ini, lintas rename?”
Terminal$ git show 8f3a1c2 # metadata + diff satu commit $ git diff a1b9d04..8f3a1c2 # selisih antara dua commit $ git log -p -- internal/product/service.go # riwayat + diff satu file $ git log --follow -- internal/product/price.go # ikut menembus rename file
Sering yang kamu butuhkan bukan seluruh history, melainkan siapa yang menyentuh satu file. git log -- path/file menyaring commit yang mengubah file tersebut, dan --follow membuat penelusuran tetap utuh meski file pernah di-rename. Tambahkan -p untuk melihat diff tiap perubahannya, sehingga evolusi sebuah file terbaca seperti cerita.
Seperti history browser yang membiarkanmu kembali ke halaman sebelumnya, git log adalah timeline proyek: tiap commit adalah titik yang bisa kamu kunjungi, bandingkan, dan pahami konteksnya.
git log —oneline —graph —all adalah perintah yang paling sering kamu butuhkan untuk orientasi. Jadikan alias (mis. git lg) lewat git config agar peta cabang selalu satu ketikan jauhnya.
Yang berharga dari history bukan kodenya saja (itu ada di file sekarang), melainkan urutan keputusan: kenapa pendekatan A dipilih lalu diganti B. Itulah sebabnya pesan commit yang menjelaskan “kenapa” membuat history jauh lebih bernilai.
Ringkasan
Loop harian yang menjaga history tetap berharga
Tracking, commit, dan history adalah satu lingkaran: kualitas dua yang pertama menentukan nilai yang ketiga.
Kamu kini punya loop harian yang utuh. Staging memberi kendali memilih perubahan dengan sadar, lebih baik git add -p ketimbang refleks git add .. Commit atomic dengan subject imperatif dan body yang menjelaskan “kenapa” membuat tiap titik history bermakna. Dan git log, git show, serta git diff mengubah history dari arsip pasif menjadi alat investigasi. Di Chapter 3 kita keluar dari satu garis lurus ini: bekerja paralel lewat branch, lalu menyatukannya dengan merge dan menyelesaikan konflik.
Yang Wajib Menempel
- Tiga kondisi file, modified, staged, committed, dan staging adalah ruang menyusun commit.
git add -pmemecah perubahan tak berkaitan;git restoretanpa—stageditu destruktif.- Commit atomic: satu ide per commit, subject imperatif maksimal 50 karakter, body menjawab “kenapa”.
git log —oneline —graph —allmemberi peta;show/diff/log —followmenjawab pertanyaan investigasi spesifik.- Kualitas commit hari ini adalah nilai history yang kamu baca berbulan-bulan kemudian.