← semua materi
19:00 Tips · 27 Oct 2026 · 19:01

Commit Message: 7 Detik yang Menyelamatkan 7 Jam Debugging

Bayangkan Senin pagi. Production down. Kamu git log --oneline — hasilnya:

fix bug
update
fix lagi
asdf
WIP
final fix beneran

Sekarang coba cari commit mana yang ngerusak. Selamat, kamu baru saja kehilangan dua jam sebelum mulai kerja.

Masalahnya bukan disiplin, tapi format

Kebanyakan orang nulis commit message buruk bukan karena malas. Karena tidak ada standar yang bisa dieksekusi. "Tulis commit yang jelas" itu imbauan. "Pakai feat: / fix: di depan" itu aturan — dan aturan bisa diotomasi.

Conventional Commits = spesifikasi ringan, cuma satu baris:

<type>(<scope opsional>): <deskripsi singkat>

[body opsional]

[footer opsional]

Type yang dipakai sehari-hari cukup 5:

Type Kapan Efek versi (semver)
feat fitur baru MINOR (1.2.0 → 1.3.0)
fix perbaiki bug PATCH (1.2.0 → 1.2.1)
docs dokumentasi saja —
refactor ubah struktur, perilaku sama —
chore deps, config, tooling —

Yang sering dilupakan: BREAKING CHANGE: di footer (atau feat!:). Ini penanda MAJOR — kalau ada yang nulis ini, berarti API berubah dan orang lain wajib baca.

Contoh nyata:

fix(auth)!: reject expired token before session lookup

Token expiry dicek setelah session di-load, jadi token kedaluwarsa
masih sempat bikin row session baru. Pindah cek ke awal middleware.

BREAKING CHANGE: requireAuth() sekarang async — semua caller
harus await.

Lihat bedanya dengan fix bug. Yang satu cerita, yang satu teka-teki.

Kenapa repot-repot? Karena changelog jadi gratis

Kekuatan asli format ini: mesin bisa bacanya. Tool seperti semantic-release atau changesets baca commit sejak tag terakhir, lalu:

  1. Kelompokkan otomatis: Features / Bug Fixes / Breaking Changes
  2. Tentukan nomor versi berikutnya
  3. Generate CHANGELOG.md
  4. Bikin tag + release notes di GitHub

Manual changelog itu pekerjaan yang selalu di-defer, lalu jadi setengah jadi. Conventional commits bikin itu nol kerja — asalkan commit-nya rapi.

Bonus yang jarang disadari: git log --grep="^fix" jadi query yang berguna. "Kapan terakhir kita sentuh auth?" → git log --oneline -- auth/ dan langsung kebaca polanya.

Tiga jebakan lapangan

1. Type jadi agama, bukan alat. Debat 20 menit soal refactor vs chore? Buang. Kalau ragu, pilih yang paling dekat, lanjut kerja.

2. Commit raksasa, message rapi. feat: tambah dashboard yang isinya 4.000 baris di 60 file. Formatnya benar, isinya tidak bisa di-review. Commit message bagus tidak menutupi commit yang terlalu besar — pecah dulu, baru beri nama.

3. Squash merge menghapus usaha orang. Kalau tim pakai squash, commit individual di branch hilang jadi satu. Itu tidak salah — justru bagus, asal judul PR yang mengikuti format. Aturan: format berlaku di commit yang masuk main, bukan di tiap save point lokal. Di lokal, wip sah-sah saja.

Cara adopsi tanpa drama: jangan langsung pasang commitlint yang memblokir CI di hari pertama. Mulai dari commit-msg hook lokal yang cuma memperingatkan. Satu sprint kemudian, baru jadikan wajib. Aturan yang dipaksakan sebelum terbiasa = tim cari jalan pintas (fix: asdf) dan formatnya mati.

Satu hal yang bisa langsung dipakai

Pasang hook peringatan 30 detik, tanpa dependency:

# .git/hooks/commit-msg
#!/bin/sh
msg=$(head -1 "$1")
echo "$msg" | grep -qE '^(feat|fix|docs|refactor|test|chore|perf|ci)(\(.+\))?!?: .{1,}' \
  || echo "⚠️  Format: <type>(<scope>): <deskripsi>  — lihat CONTRIBUTING.md"

chmod +x .git/hooks/commit-msg. Cuma memperingatkan, tidak memblokir. Naikkan jadi blokir (exit 1) kalau tim sudah terbiasa.

Kalau pakai Node, npx commitizen init cz-conventional-changelog --save-dev kasih prompt interaktif — berguna buat yang belum hafal type.

Takeaway

Commit message bukan surat buat diri sendiri minggu depan — tapi buat orang yang baca git log jam 2 pagi saat production mati, dan orang itu mungkin kamu.

Format bukan birokrasi. Format adalah cara bikin mesin kerja buat kamu: changelog otomatis, versi otomatis, riwayat yang bisa di-query. Tujuh detik ngetik type yang benar, hemat tujuh jam nanti.