Mekanisme exit code dari chapter sebelumnya berlaku untuk semua hooks — yang membedakan satu hook dari yang lain hanyalah tiga hal: momen Git menjalankannya, masukan yang diterimanya, dan apakah keluar non-zero-nya memblokir apa pun. Chapter ini memetakan sembilan hook sisi klien yang paling sering dipakai, lalu membedah tiga inti yang menanggung sebagian besar kebutuhan nyata: pre-commit, commit-msg, dan pre-push. Semua demo dijalankan pada satu repository latihan yang sama.
Peta Sembilan Hook Sisi Klien #
| Hook | Dijalankan saat | Masukan | Bisa blok? |
|---|---|---|---|
pre-commit | sebelum pesan commit ditulis | tanpa argumen | ya — commit dibatalkan |
prepare-commit-msg | sebelum editor pesan terbuka | $1 berkas pesan, $2 sumber pesan | jarang — pesannya yang diubah |
commit-msg | setelah pesan ditulis, sebelum commit lahir | $1 berkas pesan | ya — commit dibatalkan |
post-commit | setelah commit lahir | tanpa argumen | tidak — commit sudah jadi |
pre-rebase | sebelum git rebase berjalan | $1 upstream, $2 branch | ya — rebase dibatalkan |
post-merge | setelah git merge/git pull selesai | $1 flag squash | tidak — merge sudah jadi |
pre-merge-commit | setelah merge mulai, sebelum commit merge | tanpa argumen | ya — commit merge dibatalkan |
post-checkout | setelah git switch/git checkout | $1 HEAD lama, $2 HEAD baru, $3 flag branch | tidak |
pre-push | sebelum git push berangkat | $1 nama remote, $2 URL, refs di stdin | ya — push dibatalkan |
Repository latihan kita memakai pola standar sepanjang course ini — plus satu bare repo sebagai remote:
mkdir latihan-client && cd latihan-client
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
git init --bare ../pusat-client.git
git remote add origin ../pusat-client.git
printf 'situs v1\n' > situs.md
git add situs.md
GIT_AUTHOR_DATE="2026-11-06T09:00:00+07:00" GIT_COMMITTER_DATE="2026-11-06T09:00:00+07:00" \
git commit -m "Rilis situs v1"pre-commit: Gerbang Sebelum Pesan Ditulis #
pre-commit adalah hook pertama yang berjalan pada git commit — sebelum editor terbuka, sebelum pesan ditulis, jadi penulisnya dihentikan paling awal. Hook ini tidak menerima argumen; cara standar melihat apa yang akan di-commit adalah git diff --cached yang membaca staging area. Sifat inilah yang menjadikannya tempat paling populer untuk pemeriksaan kualitas: linting, jejak debug, whitespace, larangan berkas besar. Demo paling sederhananya sudah kita buktikan di chapter sebelumnya (echo + exit 1 memblokir commit), dan pembangunan versi produksinya — lengkap dengan uji nyata — menjadi fokus chapter Pre-Commit Hook
.
commit-msg: Pesan Calon Commit sebagai Berkas #
Hook kedua dalam urutan commit adalah commit-msg. Bedanya dengan pre-commit: hook ini berjalan setelah pesan ditulis — Git menyimpan draf pesan ke sebuah berkas sementara, lalu mengoper jalur berkas itu sebagai argumen pertama ($1). Hook membaca berkasnya, memeriksa format, dan keluar non-zero bila pesan melanggar aturan. Versi minimalnya:
cat > .git/hooks/commit-msg <<'HOOK'
#!/bin/sh
pesan="$(cat "$1")"
if [ ${#pesan} -lt 10 ]; then
echo "commit-msg: pesan terlalu pendek: '$pesan'" >&2
exit 1
fi
HOOK
chmod +x .git/hooks/commit-msg
printf 'situs v4\n' > situs.md
git add situs.md
git commit -m "update"Output yang Dihasilkan (perintah terakhir):
commit-msg: pesan terlalu pendek: 'update'Commit dibatalkan, staging area tetap utuh, dan pesan “update” tidak pernah menjadi commit. Mari kita bedah skripnya baris per baris:
pesan="$(cat "$1")"membaca seluruh isi berkas yang dioper Git — biasanya.git/COMMIT_EDITMSG— ke satu variabel.if [ ${#pesan} -lt 10 ]menghitung panjang string${#pesan}dan membandingkannya dengan 10.>&2mengalihkan pesan kesalahan ke stderr — konvensi hooks, karena stdout kadang ditelan oleh proses induk.exit 1membatalkan commit.
Pesan yang memenuhi syarat lolos tanpa pesan apa pun:
git commit -m "Perbarui halaman situs"Output yang Dihasilkan:
[main 5484f19] Perbarui halaman situs
1 file changed, 1 insertion(+), 1 deletion(-)Hash 5484f19 berbeda di mesin pembaca. Validasi yang serius untuk hook ini — pola Conventional Commits beserta pengujian pesan nyata — dibangun tuntas di chapter Commit-Msg Hook
.
pre-push: Argumen Remote dan Daftar Refs di stdin #
pre-push berjalan setelah git push menghitung apa yang akan dikirim, tapi sebelum jaringan disentuh — posisi terakhir untuk menahan commit yang belum siap meninggalkan mesin. Dua argumennya adalah nama remote ($1) dan URL-nya ($2); daftar refs yang akan didorong datang lewat stdin, satu baris per ref. Hook berikut menampilkan semuanya:
cat > .git/hooks/pre-push <<'HOOK'
#!/bin/sh
remote="$1"
url="$2"
echo "pre-push: sasaran = $remote ($url)"
echo "pre-push: yang akan didorong:"
while read local_ref local_sha remote_ref remote_sha; do
echo " $local_ref $local_sha -> $remote_ref"
done
HOOK
chmod +x .git/hooks/pre-push
printf 'situs v2\n' > situs.md
git add situs.md
GIT_AUTHOR_DATE="2026-11-06T09:10:00+07:00" GIT_COMMITTER_DATE="2026-11-06T09:10:00+07:00" \
git commit -m "Rilis situs v2"
git push -u origin mainOutput yang Dihasilkan (perintah terakhir):
pre-push: sasaran = origin (../pusat-client.git)
pre-push: yang akan didorong:
refs/heads/main 55729b4f1710c918cd5cd7274cadb1e8b6686b94 -> refs/heads/main
To ../pusat-client.git
* [new branch] main -> main
branch 'main' set up to track 'origin/main'.Format tiap baris stdin: local_ref local_sha remote_ref remote_sha — keempat kolom dipisah spasi. Deret angka nol pada kolom remote_sha (sebelum push pertama) menandakan ref yang belum ada di server; setelah ada, kolom itu berisi hash lama. Blokirnya tinggal mengganti loop menjadi pemeriksa:
cat > .git/hooks/pre-push <<'HOOK'
#!/bin/sh
while read local_ref local_sha remote_ref remote_sha; do
if [ "$remote_ref" = "refs/heads/main" ]; then
echo "pre-push: dorongan ke main butuh persetujuan rilis" >&2
exit 1
fi
done
HOOK
chmod +x .git/hooks/pre-push
printf 'situs v3\n' > situs.md
git add situs.md
GIT_AUTHOR_DATE="2026-11-06T09:20:00+07:00" GIT_COMMITTER_DATE="2026-11-06T09:20:00+07:00" \
git commit -m "Rilis situs v3"
git push origin mainOutput yang Dihasilkan (perintah terakhir):
pre-push: dorongan ke main butuh persetujuan rilis
error: failed to push some refs to '../pusat-client.git'Push batal sebelum berangkat — bandingkan dengan penolakan server di chapter berikutnya, yang kelihatannya sama di terminal tapi berbeda total secara kekuatan: blokir pre-push bisa dihapus penulisnya sendiri, blokir server tidak.
Hook Pasca dan yang Jarang Dipakai #
Sisanya berperan sebagai pelengkap. post-commit berjalan setelah commit lahir — cocok untuk notifikasi; git rev-parse --short HEAD di dalamnya mengambil hash commit yang barusan tersimpan:
cat > .git/hooks/post-commit <<'HOOK'
#!/bin/sh
echo "post-commit: tersimpan sebagai $(git rev-parse --short HEAD)"
HOOK
chmod +x .git/hooks/post-commit
printf 'situs v5\n' > situs.md
git add situs.md
GIT_AUTHOR_DATE="2026-11-06T09:40:00+07:00" GIT_COMMITTER_DATE="2026-11-06T09:40:00+07:00" \
git commit -m "Rilis situs v5"Output yang Dihasilkan (perintah terakhir):
post-commit: tersimpan sebagai 568c8cb
[main 568c8cb] Rilis situs v5
1 file changed, 1 insertion(+), 1 deletion(-)post-checkout menerima $1 HEAD lama, $2 HEAD baru, dan $3 bernilai 1 bila perpindahan antar-branch — kombinasi pas bila proyek perlu menyiapkan sesuatu tiap ganti branch. Hook berikut mencatat perpindahan:
cat > .git/hooks/post-checkout <<'HOOK'
#!/bin/sh
if [ "$3" = "1" ]; then
echo "post-checkout: pindah branch: $1 -> $2"
fi
HOOK
chmod +x .git/hooks/post-checkout
git switch -c fitur-galeriOutput yang Dihasilkan (perintah terakhir):
Switched to a new branch 'fitur-galeri'
post-checkout: pindah branch: 568c8cbcd7c6b930dbd68ea7e4605f96bf8f65c0 -> 568c8cbcd7c6b930dbd68ea7e4605f96bf8f65c0prepare-commit-msg mengubah draf pesan sebelum editor terbuka — dipakai template pesan commit; pre-rebase menahan rebase berbahaya; pre-merge-commit dan post-merge menjaga momen sekitar merge, yang terakhir dibedah utuh di chapter Post-Merge Hook
. Satu catatan praktis: post-merge juga terpanggil oleh git pull, karena pull pada dasarnya fetch lalu merge.
Semua hook di chapter ini berjalan di mesin penulis — dan justru itulah kelemahan strukturalnya. Kontributor mana pun bisa menghapusnya, dan repo yang di-clone memang tidak membawanya. Ketika aturan harus berlaku untuk semua orang tanpa kecuali, hooks harus pindah rumah ke mesin yang menerima push: server-side hooks, chapter berikutnya.