Mekanisme exit code sudah di tangan; sekarang hook yang benar-benar berpikir. Masalah yang dijawab bagian ini klasik: tim web-toko sepakat memakai Conventional Commits
— pesan berpola type(scope): deskripsi — tetapi Git tidak peduli; "update", "perbaiki dikit", dan "wip" tetap sah sebagai pesan commit. Hook commit-msg menutup celah itu: hook ini berjalan tepat setelah pesan ditulis dan sebelum commit lahir, membaca pesannya dari sebuah berkas, lalu menolak pesan yang melanggar pola dengan alasan yang jelas. Spesifikasi lengkap formatnya bisa dibaca di situs Conventional Commits
— tersedia juga dalam terjemahan Indonesia.
Ada satu keputusan desain sebelum menulis skrip: hook ditempatkan di folder hooks/ di dalam repository, bukan langsung di .git/hooks/. Alasannya sederhana — berkas di .git/ tidak pernah ter-version-control dan tidak ikut saat di-clone, sedangkan hooks/commit-msg yang hidup di working tree bisa di-commit, di-review, dan dibagikan. Konsekuensinya ada satu langkah pemasangan: menyalin (copy) berkas itu ke .git/hooks/ yang benar-benar dicari Git — cara kedua yang jauh lebih rapi menyusul di Bagian 4
.
Skrip Validasi di Dalam Repository #
Tulis hooks/commit-msg lengkap, lalu pasang salinannya:
mkdir hooks
cat > hooks/commit-msg <<'HOOK'
#!/bin/sh
# commit-msg — validasi pesan commit untuk web-toko.
# Git mengoper jalur berkas pesan sementara sebagai $1
# (biasanya .git/COMMIT_EDITMSG).
berkas_pesan="$1"
subjek="$(grep -v '^#' "$berkas_pesan" | sed '/^[[:space:]]*$/d' | head -n 1)"
pola='^(feat|fix|docs|chore|refactor|test)(\(.+\))?: .+'
if [ -z "$subjek" ]; then
echo "commit-msg: pesan kosong — tulis subjek dengan format type(scope): deskripsi" >&2
exit 1
fi
if ! printf '%s\n' "$subjek" | grep -qE "$pola"; then
{
echo "commit-msg: subjek ditolak: '$subjek'"
echo " format: type(scope): deskripsi — scope opsional"
echo " type: feat | fix | docs | chore | refactor | test"
echo " contoh: 'feat: tambah keranjang' atau 'fix(ui): benahi tombol bayar'"
} >&2
exit 1
fi
if [ "${#subjek}" -gt 72 ]; then
echo "commit-msg: subjek ${#subjek} karakter — maksimal 72: '$subjek'" >&2
exit 1
fi
HOOK
chmod +x hooks/commit-msg
cp hooks/commit-msg .git/hooks/commit-msg
chmod +x .git/hooks/commit-msgPerintah cp itulah pemasangannya: Git mencari hook bernama commit-msg di .git/hooks/, jadi salinan harus sampai ke sana dan tetap executable. Verifikasi keduanya:
stat -c '%A %n' .git/hooks/commit-msgOutput yang Dihasilkan:
-rwxrwxr-x .git/hooks/commit-msgMembaca Pesan dari Berkas $1 #
Mekanisme masukannya: Git menyimpan draf pesan ke berkas sementara — biasanya .git/COMMIT_EDITMSG — lalu mengoper jalurnya sebagai argumen pertama, jadi $1 di dalam skrip. Bedah baris-per-baris inti skripnya:
berkas_pesan="$1"menyimpan jalur berkas pesan — satu-satunya argumen yang Git kirim ke hookcommit-msg.grep -v '^#' "$berkas_pesan" | sed '/^[[:space:]]*$/d' | head -n 1mengambil subjek: baris pertama yang bukan komentar. Saat commit ditulis lewat editor, berkas pesan masih memuat baris petunjuk berawalan#yang baru dibuang Git setelah hook selesai — perilaku yang dibedah tuntas di Commit-Msg Hook ;sedtambahan melewati baris kosong.pola='^(feat|fix|docs|chore|refactor|test)(\(.+\))?: .+'adalah pola Conventional Commits versi web-toko: salah satu dari enamtype,scopeopsional dalam kurung, titik dua, spasi, lalu deskripsi. Pilihan enam type ini sengaja lebih ramping daripada daftar lengkap spesifikasinya — tim kecil cukup memulai dari yang paling sering terpakai.if [ -z "$subjek" ]menolak pesan kosong lebih dulu, dengan pesan yang mengajari formatnya.printf '%s\n' "$subjek" | grep -qE "$pola"menguji subjek terhadap pola;printfmenambah baris baru karenagrepmenguji per baris, dan-qmembuatnya bisu karena kita hanya butuh exit code-nya.- Blok
{ ... } >&2mencetak penolakan beserta petunjuk perbaikan ke stderr — pesan kesalahan yang hanya berkata “salah” tanpa berkata “bagaimana benarnya” hanya melahirkan frustrasi. [ "${#subjek}" -gt 72 ]menjaga subjek tetap nyaman dibaca digit log --oneline— angka yang sama dipakai alat pemeriksa pesan di CI.
Uji: “update” Ditolak, “feat: tambah keranjang” Lolos #
Fitur keranjang masih menunggu di staging area sejak Bagian 1 — bahan uji yang sempurna. Coba pesan favorit semua orang yang sedang buru-buru:
git commit -m "update"Output yang Dihasilkan:
commit-msg: subjek ditolak: 'update'
format: type(scope): deskripsi — scope opsional
type: feat | fix | docs | chore | refactor | test
contoh: 'feat: tambah keranjang' atau 'fix(ui): benahi tombol bayar'Commit batal — dan penulisnya tinggal membaca empat baris itu untuk tahu persis cara memperbaikinya. Staging area tetap utuh memuat keranjang. Sekarang ketik pesannya benar:
git commit -m "feat: tambah keranjang"Output yang Dihasilkan:
[main 9643466] feat: tambah keranjang
1 file changed, 4 insertions(+)Fitur keranjang akhirnya lahir setelah menunggu dua bagian — dan sejak commit ini, semua pesan web-toko melewati pengadilan yang sama. Terakhir, hooknya sendiri layak masuk repository:
git add hooks/commit-msg
git commit -m "chore: pasang validasi pesan commit"Output yang Dihasilkan (perintah terakhir):
[main 668d6c2] chore: pasang validasi pesan commit
1 file changed, 29 insertions(+)
create mode 100755 hooks/commit-msggit log --onelineOutput yang Dihasilkan:
668d6c2 chore: pasang validasi pesan commit
9643466 feat: tambah keranjang
e9d7cc7 feat: rintis web-tokoAda satu kejutan manis di commit terakhir: create mode 100755 — Git menyimpan bit executable bersama isi berkas, jadi salinan hooks/commit-msg di clone mana pun nanti tetap siap dieksekusi. Dan perhatikan juga bahwa commit yang memasang hook itu sendiri divalidasi oleh hook yang baru dipasangnya: pesan chore: pasang validasi pesan commit lolos pola yang berlaku mulai saat itu.
Pesan commit kini dijaga, tetapi isi berkasnya masih bebas — spasi menggantung di ujung baris, jejak debug, dan berkas raksasa bisa masuk dengan pesan yang rapi. Bagian berikutnya memasang pemeriksa kedua di gerbang yang sama: Bagian 3: Otomasi Pemeriksaan .
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
scripts/validate-commit-message.sh
Unduh berkas#!/bin/sh
# validate-commit-message.sh — inti validasi pesan commit web-toko.
# Dipanggil oleh hooks/commit-msg dengan $1 = berkas pesan sementara
# (biasanya .git/COMMIT_EDITMSG). Aturan: Conventional Commits.
berkas_pesan="$1"
subjek="$(grep -v '^#' "$berkas_pesan" | sed '/^[[:space:]]*$/d' | head -n 1)"
pola='^(feat|fix|docs|chore|refactor|test)(\(.+\))?: .+'
if [ -z "$subjek" ]; then
echo "commit-msg: pesan kosong — tulis subjek dengan format type(scope): deskripsi" >&2
exit 1
fi
if ! printf '%s\n' "$subjek" | grep -qE "$pola"; then
{
echo "commit-msg: subjek ditolak: '$subjek'"
echo " format: type(scope): deskripsi — scope opsional"
echo " type: feat | fix | docs | chore | refactor | test"
echo " contoh: 'feat: tambah keranjang' atau 'fix(ui): benahi tombol bayar'"
} >&2
exit 1
fi
if [ "${#subjek}" -gt 72 ]; then
echo "commit-msg: subjek ${#subjek} karakter — maksimal 72: '$subjek'" >&2
exit 1
fi