Micro code review di git hook berguna ketika tim ingin menangkap regresi sedini mungkin, bahkan sebelum commit masuk ke branch lokal. Ide utamanya bukan memindahkan seluruh quality gate ke laptop developer, tetapi menaruh pemeriksaan yang cepat, deterministik, dan relevan pada titik yang paling dekat dengan perubahan.

Jika dirancang dengan benar, hook lokal memberi feedback loop yang sangat pendek: developer tahu ada masalah saat commit atau sebelum push, bukan menunggu pipeline CI selesai. Namun manfaat ini hanya terasa jika pemeriksaan yang dijalankan memang ringan, stabil, dan tidak sering menghasilkan false positive. Karena itu, fokus utamanya harus pada strategi testing dan reliability, bukan pada alat tertentu.

Mengapa regresi perlu dicegah sejak commit

Regresi sering muncul bukan karena bug besar, melainkan karena perubahan kecil yang lolos tanpa validasi dasar: import rusak, test terkait gagal, aturan commit tidak konsisten, atau perubahan konfigurasi yang mematahkan alur build. Menunggu CI untuk semua jenis masalah membuat feedback terlambat, terutama bila pipeline penuh membutuhkan beberapa menit atau lebih.

Git hook memberi lapisan pemeriksaan lokal yang berada di antara editor dan CI. Dalam konteks ini, micro code review berarti pemeriksaan singkat terhadap perubahan yang baru dibuat: file apa yang berubah, risiko dasar apa yang muncul, dan validasi minimum apa yang perlu dijalankan sebelum perubahan dianggap layak diteruskan.

Tujuan yang realistis untuk hook lokal

  • Mendeteksi kesalahan cepat seperti syntax error, lint error penting, atau test kecil yang langsung terkait perubahan.
  • Menjaga disiplin commit, misalnya format pesan commit dan pencegahan file sensitif ikut ter-commit.
  • Mengurangi noise di CI dengan menyaring kesalahan yang seharusnya bisa diketahui lebih awal.
  • Mempercepat iterasi developer tanpa menggantikan validasi penuh di CI.

Hook lokal bukan tempat yang tepat untuk test integrasi besar, e2e yang berat, benchmark performa, atau pemeriksaan yang bergantung pada lingkungan yang sulit direproduksi di laptop semua anggota tim.

Lapisan verifikasi: pre-commit, commit-msg, pre-push, lalu CI

Workflow yang sehat biasanya bertingkat. Semakin dekat ke momen commit, semakin kecil dan cepat validasinya. Semakin dekat ke merge atau deploy, semakin lengkap cakupannya.

1. Pre-commit: validasi paling cepat dan paling aman

pre-commit sebaiknya hanya berisi pemeriksaan yang selesai dalam hitungan detik dan sangat jarang flaky. Targetnya adalah file yang di-stage, bukan seluruh repository, jika memungkinkan.

Pemeriksaan yang cocok di pre-commit:

  • Formatter pada file yang di-stage.
  • Lint dasar atau static check cepat.
  • Syntax check.
  • Secret scan ringan untuk pola yang jelas.
  • Subset unit test yang benar-benar kecil, bila bisa dipetakan ke file yang berubah.

Contoh hook pre-commit sederhana:

#!/bin/sh
set -e

STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)

if [ -z "$STAGED_FILES" ]; then
  exit 0
fi

# Contoh: cek file JavaScript/TypeScript yang di-stage
JS_FILES=$(echo "$STAGED_FILES" | grep -E '\.(js|jsx|ts|tsx)$' || true)

if [ -n "$JS_FILES" ]; then
  echo "Menjalankan formatter/lint pada file yang di-stage..."
  echo "$JS_FILES" | xargs npx eslint
fi

# Contoh: cegah file .env ikut ter-commit
if echo "$STAGED_FILES" | grep -E '(^|/)\.env($|\.)' >/dev/null; then
  echo "Commit ditolak: file .env terdeteksi di stage"
  exit 1
fi

Prinsip pentingnya: jangan memblokir commit untuk hal yang tidak deterministik. Jika sebuah pemeriksaan kadang gagal kadang lolos tanpa perubahan kode, itu kandidat buruk untuk pre-commit.

2. Commit-msg: jaga kualitas metadata commit

commit-msg sering diremehkan, padahal berguna untuk menjaga histori tetap dapat dibaca dan diotomasi. Hook ini tidak mencegah regresi fungsional secara langsung, tetapi membantu reliability proses pengembangan: changelog lebih konsisten, release automation lebih mudah, dan investigasi bug lebih cepat.

Contoh hook commit-msg:

#!/bin/sh
set -e

COMMIT_MSG_FILE="$1"
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")

# Contoh aturan sederhana: type(scope): subject
if ! echo "$COMMIT_MSG" | grep -Eq '^(feat|fix|refactor|test|docs|chore)(\([a-z0-9_-]+\))?: .+'; then
  echo "Format commit message tidak valid. Gunakan misalnya: fix(auth): handle token refresh"
  exit 1
fi

Hook ini aman karena cepat, jelas, dan tidak bergantung pada lingkungan runtime aplikasi.

3. Pre-push: smoke test sebelum perubahan keluar dari mesin lokal

pre-push adalah tempat yang lebih tepat untuk menjalankan pemeriksaan yang sedikit lebih berat. Di sini Anda bisa menaruh smoke test, subset unit test yang lebih luas, atau verifikasi build minimal. Developer memang harus menunggu lebih lama dibanding pre-commit, tetapi momen push sudah lebih jarang daripada save atau commit.

Pemeriksaan yang cocok di pre-push:

  • Smoke test untuk jalur aplikasi paling penting.
  • Subset regression test untuk area yang rawan rusak.
  • Build check ringan.
  • Type check atau static analysis yang lebih luas.

Contoh hook pre-push:

#!/bin/sh
set -e

echo "Menjalankan smoke test sebelum push..."

# Contoh generik: sesuaikan dengan stack Anda
npm test -- --runInBand smoke
npm run build -- --mode=check

Smoke test di sini bukan pengganti test suite penuh. Tujuannya hanya menjawab pertanyaan sederhana: apakah alur utama aplikasi masih hidup setelah perubahan terakhir?

4. CI: lapisan akhir yang wajib dan lebih lengkap

Semua validasi penting tetap harus ada di CI, karena hook lokal bisa dilewati, dinonaktifkan, atau berjalan di lingkungan yang berbeda antar developer. CI adalah sumber kebenaran bersama untuk branch protection dan merge gate.

Yang sebaiknya dipindahkan ke CI:

  • Test suite penuh.
  • Integration test dan end-to-end test.
  • Security scan yang berat.
  • Cross-platform validation.
  • Pemeriksaan yang butuh service eksternal atau environment tertentu.
  • Regression gate resmi sebelum merge ke branch utama.

Aturan praktis: jika sebuah pemeriksaan butuh waktu lama, sering flaky, atau sulit direproduksi di semua laptop, jangan jadikan ia blocker di hook lokal. Taruh di CI.

Jenis pemeriksaan yang aman dijalankan cepat

Agar micro code review di git hook benar-benar membantu, pilih pemeriksaan yang memiliki rasio nilai terhadap waktu yang tinggi.

Pemeriksaan paling aman untuk hook lokal

  • Format dan lint file yang berubah: cepat, jelas, dan mudah diperbaiki.
  • Syntax/type check ringan: efektif menangkap kerusakan mekanis sebelum push.
  • Test unit kecil yang stabil: khususnya jika dapat ditargetkan ke area yang diubah.
  • Secret detection berbasis pola sederhana: misalnya private key atau token yang jelas formatnya.
  • Validasi commit message: meningkatkan konsistensi proses tanpa membebani mesin.

Pemeriksaan yang perlu hati-hati

  • Test yang menyentuh database/network: mudah lambat dan flaky.
  • Coverage gate: sering tidak sebanding untuk hook lokal.
  • Scan keamanan besar: lebih cocok di CI terjadwal atau pipeline merge.
  • Test UI/e2e: umumnya terlalu berat untuk dijalankan pada setiap commit.

Jika tim ingin menambahkan micro AI code reviewer pada hook, posisikan ia sebagai advisory, bukan blocking gate, kecuali aturannya sangat sempit dan deterministik. Misalnya, reviewer berbasis AI boleh memberi catatan tentang pola rawan regresi pada diff kecil, tetapi keputusan final tetap harus ditopang oleh test dan rule yang bisa diverifikasi konsisten.

Mengurangi false positive agar developer tidak mem-bypass hook

Hook yang terlalu sering salah akan segera kehilangan legitimasi. Begitu developer merasa pemeriksaan lokal lebih sering mengganggu daripada membantu, mereka akan mencari cara melewatinya.

Penyebab umum false positive

  • Pemeriksaan membaca seluruh repo, padahal perubahan hanya satu file.
  • Tool bergantung pada state lokal yang tidak konsisten.
  • Test tidak deterministik atau sensitif waktu.
  • Hook menjalankan rule yang relevansinya rendah terhadap perubahan.
  • Perbedaan environment antarmesin tidak dikendalikan.

Cara membatasinya

  1. Scope ke file yang di-stage bila memungkinkan.
  2. Utamakan pemeriksaan deterministik, hasilnya harus sama bila input sama.
  3. Beri output yang jelas, tunjukkan file, rule, dan cara memperbaiki.
  4. Gunakan timeout mental yang ketat: jika terlalu terasa lambat, pindahkan ke tahap berikutnya.
  5. Pisahkan warning dan blocker: tidak semua temuan harus menggagalkan commit.
  6. Audit hook secara berkala: hapus rule yang mahal tetapi jarang memberi nilai.

Salah satu kesalahan umum adalah memasukkan terlalu banyak aturan sekaligus. Lebih baik mulai dari 2-3 validasi yang hampir selalu benar, lalu tambahkan secara bertahap setelah tim percaya pada sinyal yang dihasilkan.

Hubungan dengan flaky test, smoke test, regression gate, dan feedback loop

Flaky test adalah musuh utama hook lokal

Test flaky merusak kepercayaan. Di CI saja sudah merepotkan, apalagi di laptop developer saat commit. Jika sebuah test kadang gagal karena timing, race condition, data bersama, atau ketergantungan eksternal, jangan taruh ia di hook lokal.

Untuk test yang masih ingin dipakai sebagai penjaga lokal, pastikan:

  • Tidak bergantung pada network nyata.
  • Tidak bergantung pada jam sistem atau urutan eksekusi yang rapuh.
  • Dapat dijalankan berulang dengan hasil konsisten.
  • Setup dan teardown jelas.

Smoke test sebagai alarm cepat

Smoke test cocok untuk pre-push karena fokusnya sempit: jalur login, endpoint utama, atau proses build minimal. Ia bukan bukti bahwa sistem sepenuhnya sehat, tetapi cukup baik untuk mencegah push yang jelas-jelas rusak.

Regression gate sebagai filter resmi

Regression gate sebaiknya tetap berada di CI. Di sinilah test suite yang lebih lengkap berjalan dan menentukan apakah branch layak digabungkan. Hook lokal membantu mengurangi kegagalan yang seharusnya bisa tertangkap lebih awal, sedangkan CI memastikan standar yang sama berlaku untuk semua orang.

Feedback loop developer yang sehat

Urutannya idealnya seperti ini:

  1. Developer menulis kode dan menjalankan test saat bekerja.
  2. pre-commit memberi feedback instan untuk masalah mekanis.
  3. commit-msg menjaga histori tetap konsisten.
  4. pre-push menjalankan smoke test atau subset regression test.
  5. CI menjalankan validasi penuh sebagai gate terakhir.

Semakin cepat sinyal muncul, semakin murah biaya perbaikannya. Namun kecepatan tanpa reliabilitas hanya menciptakan gangguan. Karena itu, desain hook harus selalu menyeimbangkan latency, cakupan, dan akurasi.

Contoh alur implementasi yang praktis

Struktur hook bergantung pada tool pilihan tim, tetapi prinsip implementasinya sama. Simpan script dalam repository, lalu hubungkan Git agar semua anggota tim memakai definisi hook yang sama.

repo/
  scripts/
    hooks/
      pre-commit
      commit-msg
      pre-push

Aktifkan hook dari folder versi kontrol:

git config core.hooksPath scripts/hooks
chmod +x scripts/hooks/pre-commit scripts/hooks/commit-msg scripts/hooks/pre-push

Dengan pendekatan ini, definisi hook tidak tersembunyi di mesin masing-masing developer. Tim bisa mereview perubahan hook seperti file kode biasa.

Contoh pembagian tanggung jawab

  • pre-commit: formatter, lint file staged, cek secret, syntax check.
  • commit-msg: format pesan commit.
  • pre-push: smoke test, build check, subset unit/integration yang kecil dan stabil.
  • CI: test suite penuh, security scan, matrix environment, regression gate resmi.

Kapan hook lokal berguna, dan kapan harus langsung mengandalkan CI

Gunakan hook lokal jika

  • Masalah dapat dideteksi cepat dari perubahan lokal.
  • Hasilnya stabil dan reproduktif.
  • Biaya menjalankannya lebih kecil daripada menunggu CI gagal.
  • Perbaikannya bisa dilakukan segera oleh developer yang sedang bekerja.

Pindahkan ke CI jika

  • Pemeriksaan memerlukan environment terstandar.
  • Waktu eksekusi mulai mengganggu ritme kerja.
  • Sering menghasilkan false positive atau flaky.
  • Perlu konsistensi lintas OS, runtime, atau service eksternal.
  • Hook mudah menjadi beban komputasi besar pada mesin lokal.

Keputusan ini bukan sekali jadi. Saat codebase tumbuh, sebagian rule yang dulu nyaman di lokal mungkin perlu dipindah ke CI. Sebaliknya, rule yang dulu berat bisa menjadi ringan setelah dioptimalkan atau dipersempit cakupannya.

Checklist implementasi bertahap untuk tim kecil

Untuk tim kecil, kunci keberhasilan adalah bertahap dan terukur. Jangan mulai dari sistem yang terlalu ambisius.

  1. Petakan masalah yang paling sering lolos ke CI
    Contoh: lint error, secret ter-commit, commit message buruk, atau test unit inti sering gagal setelah push.
  2. Pilih 2-3 pemeriksaan lokal yang paling murah dan paling bernilai
    Biasanya formatter/lint file staged, commit-msg validation, dan satu smoke test kecil.
  3. Simpan hook di dalam repository
    Gunakan core.hooksPath agar konfigurasi tidak tersebar.
  4. Pastikan output error mudah dipahami
    Developer harus langsung tahu apa yang gagal dan bagaimana memperbaikinya.
  5. Ukur waktu eksekusi
    Jika pre-commit terasa lambat, kurangi cakupan atau pindahkan sebagian ke pre-push.
  6. Tandai mana blocker dan mana advisory
    Misalnya AI review atau catatan style tertentu cukup menjadi warning, bukan penolak commit.
  7. Audit flaky test sebelum memasukkannya ke hook
    Jangan gunakan test yang belum stabil sebagai gate lokal.
  8. Pertahankan CI sebagai otoritas akhir
    Hook lokal mempercepat feedback, bukan menggantikan pipeline bersama.
  9. Review efektivitas setiap beberapa sprint
    Hapus pemeriksaan yang mahal tetapi jarang menangkap masalah. Tambahkan rule baru hanya jika ada kebutuhan nyata.

Kesalahan umum yang perlu dihindari

  • Menjalankan seluruh test suite di pre-commit.
  • Mengandalkan hook lokal tanpa gate di CI.
  • Menggunakan pemeriksaan AI sebagai blocker tanpa verifikasi deterministik.
  • Tidak mem-versioning script hook di repository.
  • Membiarkan hook diam-diam memodifikasi file tanpa memberi tahu developer.
  • Tidak menyediakan jalur debugging saat hook gagal di mesin tertentu.

Tips debugging saat hook bermasalah

  • Jalankan script hook secara manual dari terminal untuk melihat output lengkap.
  • Tambahkan set -x sementara pada shell script untuk melacak perintah yang dieksekusi.
  • Pastikan path tool benar dan dependency lokal sudah terpasang.
  • Periksa apakah hook membaca file staged atau file working tree yang belum di-stage.
  • Bandingkan environment lokal dengan CI jika hasilnya berbeda.

Penutup

Micro code review di git hook untuk cegah regresi sejak commit efektif jika ditempatkan sebagai lapisan verifikasi ringan, bukan sebagai pengganti CI. Pre-commit cocok untuk pemeriksaan mekanis yang cepat, commit-msg untuk konsistensi histori, pre-push untuk smoke test dan subset regression test, sedangkan CI tetap menjadi regression gate resmi.

Jika tim kecil ingin mulai, fokuslah pada reliability lebih dulu: pilih rule yang cepat, deterministik, dan benar-benar membantu. Begitu feedback loop menjadi singkat dan tepercaya, developer akan lebih jarang mendorong perubahan yang jelas rusak, dan CI bisa difokuskan pada validasi yang memang layak dijalankan terpusat.