Hook

Menjalankan skrip otomatis pada titik tertentu melalui hook pre-commit dan commit-msg.

Daftar isi

Hook (hook) adalah skrip yang dijalankan Git pada titik-titik tertentu dalam alurnya, dan dua titik yang paling sering dipakai adalah sebelum commit dibuat dan saat pesan commit sedang divalidasi. Topik ini membaca skrip pre-commit dan commit-msg, memasangnya, dan mengujinya pada commit yang lolos maupun ditolak. Dengan hook, aturan proyek yang paling sering dilanggar dijaga oleh mesin, bukan oleh ingatan.

Lokasi dan kontrak hook#

Seluruh hook tersimpan pada folder .git/hooks/, dan Git mengedarkan contoh berakhiran .sample yang dapat dijadikan titik mulai. Skrip yang aktif tidak membawa akhiran, memakai izin executable, dan dijalankan dengan aturan yang lurus: keluaran nol melanjutkan alur, keluaran bukan nol menghentikannya. Pesan yang ditulis skrip ke keluaran tampil pada terminal pengguna, sehingga alasan penolakan perlu dituliskan secara jelas.

Hook bersifat lokal dan tidak ikut terkirim bersama commit, karena folder .git tidak pernah menjadi bagian riwayat. Konsekuensinya, hook yang dipakai bersama perlu disalin ke repository melalui berkas biasa dan dipasang oleh setiap anggota, atau diarahkan melalui kunci konfigurasi core.hooksPath menuju folder yang dikelola proyek.

Hook pre-commit#

Hook pre-commit dijalankan sebelum pesan commit ditanyakan, sehingga menjadi tempat memeriksa isi yang akan di-commit. Contoh yang dipakai di sini menolak commit yang menambahkan kata RAHASIA pada isi yang di-stage, dan skripnya ditulis langsung ke posisinya pada repository latihan.

bash
# tanggal commit ditetapkan agar keluaran contoh dapat direproduksi secara persis
export GIT_AUTHOR_DATE="2026-11-01T09:00:00+07:00"
export GIT_COMMITTER_DATE="2026-11-01T09:00:00+07:00"
bash
rm -rf /tmp/lab-hook
mkdir /tmp/lab-hook
cd /tmp/lab-hook
git init -b main
git config user.name "Budi"
git config user.email "[email protected]"
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/sh
# menolak commit yang menambahkan kata RAHASIA pada isi yang di-stage
if git diff --cached -U0 | grep -q '^+.*RAHASIA'; then
  echo "commit ditolak: berkas yang di-stage memuat kata RAHASIA" >&2
  exit 1
fi
EOF
chmod +x .git/hooks/pre-commit
printf "Kunci api = RAHASIA-123\n" > konfigurasi.txt
git add konfigurasi.txt
git commit -m "Tambah konfigurasi"
text Keluaran
Initialized empty Git repository in /tmp/lab-hook/.git/
commit ditolak: berkas yang di-stage memuat kata RAHASIA

Commit ditolak, dan pesan skrip menjadi satu-satunya keluaran karena Git menghentikan alur sebelum commit dibuat. Skripnya membaca git diff --cached, yaitu isi staging area, sehingga pemeriksaannya tepat menyasar apa yang akan masuk commit, bukan isi working directory. Perbaiki isinya, lalu commit berjalan normal.

bash
printf "Kunci api diambil dari variabel lingkungan.\n" > konfigurasi.txt
git add konfigurasi.txt
git commit -m "Baca kunci api dari lingkungan"
text Keluaran
[main (root-commit) 8fba54b] Baca kunci api dari lingkungan
 1 file changed, 1 insertion(+)
 create mode 100644 konfigurasi.txt

Hook commit-msg#

Hook commit-msg menerima satu argumen berupa berkas yang memuat pesan commit, sehingga cocok untuk menegakkan konvensi pesan. Contoh berikut menolak pesan yang baris pertamanya lebih pendek dari sepuluh karakter.

bash
cat > .git/hooks/commit-msg << 'EOF'
#!/bin/sh
# menolak pesan commit yang baris pertamanya lebih pendek dari 10 karakter
pesan=$(head -n 1 "$1")
if [ "${#pesan}" -lt 10 ]; then
  echo "commit ditolak: baris pertama pesan minimal 10 karakter" >&2
  exit 1
fi
EOF
chmod +x .git/hooks/commit-msg
git commit --allow-empty -m "pendek"
git commit --allow-empty -m "Tambah catatan rilis"
text Keluaran
commit ditolak: baris pertama pesan minimal 10 karakter
[main c7ffa84] Tambah catatan rilis

Commit dengan pesan pendek ditolak, sedangkan pesan yang memenuhi syarat lolos tanpa penyelaan. Bentuk validasi ini yang biasanya dikembangkan lebih jauh, misalnya menuntut awalan feat: atau fix: sesuai konvensi pesan commit yang dibahas pada modul commit yang baik, dan skripnya tumbuh dari bentuk yang sama.

Memilih titik hook yang tepat#

Git menyediakan puluhan titik hook, dan menempatkan pemeriksaan pada titik yang tepat menentukan nilai peringatannya. Titik pra-tindakan seperti pre-commit, pre-push, dan pre-rebase dapat menghentikan langkah sebelum akibatnya terjadi, sehingga cocok untuk pemeriksaan yang hasilnya mengubah isi riwayat. Titik pasca-tindakan seperti post-commit dan post-merge tidak dapat menghentikan apa pun, tetapi tepat untuk pemberitahuan, misalnya memperbarui pengaturan lingkungan setelah merge.

Kontrak argumen tiap titik berbeda dan selalu tercantum pada dokumentasi githooks, sehingga setiap skrip baru dimulai dari membaca halaman itu. Dua hal yang menentukan keberhasilan hook di tim adalah kecepatan dan pesannya. Pemeriksaan yang lambat membuat pengguna menonaktifkan hook secara diam-diam, sedangkan pesan penolakan yang tidak menjelaskan cara perbaikan membuat pengguna mengulang commit dengan cara yang keliru.

Aturan yang dibuat hook pun perlu disepakati sebelum dituliskan, karena hook menegakkan keputusan tim, bukan membuatnya. Aturan yang wajar menempati posisi pertama, seperti larangan kredensial dan syarat pesan commit, sedangkan selera penataan kode lebih baik diserahkan pada alat pemformat yang dijalankan hook, alih-alih ditulis ulang sebagai skrip tersendiri.

Menjaga hook tetap milik tim#

Hook yang ditulis langsung ke .git/hooks/ hidup hanya pada satu mesin, dan kekuatan aturannya hilang begitu rekan kerja meng-clone repository tanpa pemasangan yang sama. Dua cara menjaga kebersamaannya, dan keduanya mengangkat skrip dari .git menjadi bagian proyek. Cara pertama menyimpan skrip pada folder dalam repository, misalnya hooks/, lalu setiap clone menjalankan pemasangan yang menyalinnya dengan izin executable.

Cara kedua memanfaatkan kunci konfigurasi core.hooksPath yang mengarahkan Git ke folder lain, sehingga tidak ada penyalinan yang diperlukan.

bash
mkdir hooks
git mv .git/hooks/pre-commit hooks/pre-commit 2>/dev/null || true
git config core.hooksPath hooks
chmod +x hooks/pre-commit
git config core.hooksPath
text Keluaran
chmod: cannot access 'hooks/pre-commit': No such file or directory
hooks

Sejak penyetelan itu, seluruh hook dijalankan dari folder hooks/ milik repository, dan skripnya dapat di-commit sebagaimana kode biasa sehingga seluruh anggota tim mewarisinya. Trade-off kecilnya nyata: perintah git init tidak lagi mengedarkan contoh ke folder itu, dan hook yang masih default tidak berlaku lagi sebelum dipindahkan.

Ringkasan#

  • Hook tersimpan pada .git/hooks/, aktif tanpa akhiran dengan izin executable, dan keluaran bukan nol menghentikan alur.
  • Pre-commit memeriksa isi staging area sebelum commit dibuat, dan commit-msg memvalidasi pesan melalui berkas argumennya.
  • Hook tidak ikut terkirim, sehingga skrip bersama dikelola dalam repository dan diarahkan melalui core.hooksPath.
  • Penolakan hook harus disertai pesan yang jelas, karena pesan itulah yang dilihat pengguna pada terminal.

Referensi#