1. Git Menyimpan Snapshot, Bukan Perbedaan
Sistem kontrol versi lama seperti SVN menyimpan daftar perubahan per berkas. Git bekerja berbeda: setiap commit adalah potret utuh seluruh proyek pada saat itu. Berkas yang tidak berubah tidak disalin ulang — Git cukup menunjuk ke objek yang sudah ada.
- Blob — isi sebuah berkas. Tidak menyimpan nama berkas.
- Tree — sebuah direktori. Berisi daftar nama berkas beserta blob/tree yang ditunjuknya.
- Commit — menunjuk ke satu tree akar, ditambah pengarang, pesan, waktu, dan commit induk.
- Tag — penunjuk bernama ke sebuah objek, biasanya commit, dengan pesan dan penanda tangan.
Nama tiap objek adalah hash SHA-1 dari isinya. Konsekuensinya penting: dua berkas dengan isi identik hanya disimpan sekali, dan mengubah satu byte saja pada commit lama akan mengubah hash-nya beserta seluruh commit sesudahnya. Inilah yang membuat riwayat Git tidak bisa dipalsukan diam-diam.
# Lihat jenis sebuah objek git cat-file -t HEAD # => commit # Lihat isinya git cat-file -p HEAD # tree 9f2b3c... # parent 4a1de8... # author Budi <[email protected]> 1712345678 +0700 # committer Budi <[email protected]> 1712345678 +0700 # # menambahkan validasi form login # Telusuri tree-nya git cat-file -p HEAD^{tree} # Hash sebuah isi tanpa menyimpannya echo "halo" | git hash-object --stdin
2. Tiga Wilayah Git
Working Directory Staging Area (Index) Repository (.git)
berkas yang Anda edit calon commit berikutnya riwayat permanen
│ │ │
│──── git add ────────────>│ │
│ │──── git commit ─────────>│
│<─── git restore ─────────│ │
│<─────────────── git restore --source=HEAD ──────────│
Hampir semua kebingungan pemula soal Git berasal dari tidak memisahkan tiga wilayah ini. git status selalu memberi tahu Anda berkas berada di wilayah mana.
git status git status -s # ringkas: XY nama-berkas # Kolom pertama = keadaan di staging area # Kolom kedua = keadaan di working directory # # M_ = sudah di-stage, siap commit # _M = berubah tapi belum di-stage # MM = sudah di-stage, LALU diubah lagi setelahnya # ?? = berkas baru yang belum dilacak Git
3. Menyusun Commit dengan Rapi
# Menambahkan berkas ke staging area git add berkas.js git add . # semua perubahan di direktori sekarang git add -A # semua perubahan di seluruh repositori # Memilih BAGIAN dari sebuah berkas -- sangat berguna git add -p berkas.js # y = ambil bagian ini, n = lewati, s = pecah lagi jadi lebih kecil, # e = sunting manual, q = keluar # Melihat apa yang akan masuk ke commit git diff # working directory vs staging area git diff --staged # staging area vs commit terakhir git diff HEAD # working directory vs commit terakhir
git add -p mengubah cara Anda bekerja
Anda sering menyelesaikan dua hal berbeda dalam satu sesi ngoding. git add -p memungkinkan Anda memecahnya menjadi dua commit yang bersih dan terpisah, alih-alih satu commit campur aduk berjudul "perbaikan macam-macam". Riwayat yang bersih membuat git bisect dan git revert menjadi jauh lebih berguna nanti.
4. Menulis Pesan Commit yang Berguna
git commit -m "perbaiki kebocoran koneksi pada pool database" # Pesan panjang dengan badan penjelasan git commit # Baris 1 : ringkasan maksimal ~50 karakter, kalimat perintah # Baris 2 : kosong # Baris 3+ : KENAPA perubahan ini dibuat, bukan APA yang diubah
Format yang banyak dipakai karena bisa dibaca mesin untuk membuat changelog dan menentukan versi otomatis:
feat(auth): tambahkan login dengan Google fix(api): tangani timeout pada pemanggilan layanan pembayaran docs(readme): perbarui langkah instalasi refactor(db): pisahkan query builder dari repository perf(cache): kurangi round-trip Redis pada endpoint katalog test(order): tambahkan kasus uji pembatalan pesanan chore(deps): naikkan versi driver postgres # Perubahan yang merusak kompatibilitas feat(api)!: ganti format respons error menjadi RFC 7807
Awalan feat menaikkan versi minor, fix menaikkan patch, dan tanda ! atau footer BREAKING CHANGE: menaikkan versi mayor.
5. HEAD, Branch, dan Referensi
Branch di Git hanyalah sebuah berkas teks berisi hash commit. Itu sebabnya membuat branch di Git nyaris tanpa biaya, berbeda dengan SVN yang menyalin seluruh direktori.
cat .git/HEAD # ref: refs/heads/main cat .git/refs/heads/main # 4a1de8f9c2b3... # Notasi penunjuk relatif HEAD # commit tempat Anda berada sekarang HEAD~1 # satu commit ke belakang (induk) HEAD~3 # tiga commit ke belakang HEAD^ # induk pertama HEAD^2 # induk KEDUA -- hanya ada pada merge commit
6. Membatalkan: reset, restore, revert
Tiga perintah ini sering tertukar. Bedanya terletak pada wilayah mana yang mereka sentuh.
| Perintah | Yang berubah | Aman untuk riwayat publik? |
|---|---|---|
git restore berkas | Working directory saja | Ya |
git restore --staged berkas | Staging area saja | Ya |
git reset --soft HEAD~1 | Hanya penunjuk branch; perubahan tetap di staging | Tidak |
git reset --mixed HEAD~1 | Branch + staging area (default) | Tidak |
git reset --hard HEAD~1 | Semuanya — perubahan hilang | Tidak |
git revert <commit> | Membuat commit BARU yang membatalkan | Ya — ini yang benar untuk branch bersama |
Gunakan git revert untuk commit yang sudah dipush ke branch bersama. git reset menulis ulang riwayat; bila riwayat itu sudah dipakai orang lain, Anda memaksa semua rekan tim membereskan kekacauan di repositori lokal mereka masing-masing.
7. Jaring Pengaman: reflog
# Riwayat SEMUA perpindahan HEAD, termasuk yang "hilang"
git reflog
# 4a1de8f HEAD@{0}: reset: moving to HEAD~1
# 9c2b3f1 HEAD@{1}: commit: menambahkan fitur ekspor
# 7e4a2d8 HEAD@{2}: checkout: moving from main to fitur-baru
# Memulihkan commit yang terlanjur di-reset --hard
git reset --hard 9c2b3f1
# atau selamatkan ke branch baru
git branch penyelamat 9c2b3f1
Selama commit pernah dibuat, ia tercatat di reflog selama kurang lebih 90 hari sebelum garbage collector membersihkannya. Sebelum panik karena reset --hard, jalankan git reflog — kemungkinan besar pekerjaan Anda masih ada di sana.