Gerbang kualitas kini berdiri di mesin Budi — tetapi gerbang yang hanya teruji oleh kebetulan bukan gerbang, hanya keberuntungan. Bagian penutup mengerjakan dua pekerjaan terakhir. Pertama, seluruh pertahanan diuji sistematis: tujuh kasus uji disusun dalam tabel, dijalankan nyata, dan dicocokkan dengan hasil yang diharapkan. Kedua, hasil kerja dipasangkan ke mesin rekan tim: salinan di .git/hooks/ dibuang, digantikan core.hooksPath yang menunjuk folder versioned — lalu clone baru oleh Siti membuktikan celah sekaligus solusinya.
Tabel Kasus Uji #
Ujian ini memakai satu fitur baru sebagai kelinci percobaan: modul ulasan pelanggan pada src/ulasan.js. Tujuh kasusnya mencakup tiga pesan jelek, tiga isi berkas kotor, dan satu kasus sehat:
| Kasus | Yang diuji | Input | Hasil yang diharapkan |
|---|---|---|---|
| K1 | pesan tanpa format sama sekali | update | DITOLAK oleh commit-msg |
| K2 | pesan deskriptif tapi tanpa type | perbaiki bug ulasan | DITOLAK oleh commit-msg |
| K3 | format benar, subjek 93 karakter | feat(ulasan): tambah modul ulasan beserta … | DITOLAK oleh commit-msg |
| K4 | trailing whitespace pada berkas staged | src/ulasan.js | DITOLAK oleh pre-commit |
| K5 | jejak debug pada berkas staged | console.log di src/ulasan.js | DITOLAK oleh pre-commit |
| K6 | berkas melebihi 1 MiB | aset/banner.bin | DITOLAK oleh pre-commit |
| K7 | pesan dan berkas sehat | modul ulasan bersih | LULUS — commit lahir |
Siapkan berkasnya, lalu mulai dari tiga pesan jelek — semuanya dijalankan tanpa mengubah isi staging area:
printf '// Modul ulasan pelanggan untuk web-toko.\nfunction tampilkanUlasan(daftar) {\n return daftar.slice(0, 10);\n}\n' > src/ulasan.js
git add src/ulasan.js
git commit -m "update"
git commit -m "perbaiki bug ulasan"
git commit -m "feat(ulasan): tambah modul ulasan beserta tampilan bintang filter kategori dan urutan terbaru"Output yang Dihasilkan (perintah git commit -m "update"):
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'Output yang Dihasilkan (perintah git commit -m "perbaiki bug ulasan"):
commit-msg: subjek ditolak: 'perbaiki bug ulasan'
format: type(scope): deskripsi — scope opsional
type: feat | fix | docs | chore | refactor | test
contoh: 'feat: tambah keranjang' atau 'fix(ui): benahi tombol bayar'Output yang Dihasilkan (perintah git commit -m "feat(ulasan): tambah …"):
commit-msg: subjek 93 karakter — maksimal 72: 'feat(ulasan): tambah modul ulasan beserta tampilan bintang filter kategori dan urutan terbaru'Kasus K3 layak diperhatikan: formatnya sudah benar — type, scope, titik dua, spasi — tetapi subjek 93 karakter tetap ditolak karena melewati batas 72. Gerbang kita membaca pesan sampai tuntas, bukan sekadar mengenali awalnya.
Lanjut ke K4: tulis ulang berkas dengan dua spasi menggantung di ujung baris kedua:
printf '// Modul ulasan pelanggan untuk web-toko.\nfunction tampilkanUlasan(daftar) { \n return daftar.slice(0, 10);\n}\n' > src/ulasan.js
git add src/ulasan.js
git commit -m "feat(ulasan): tambah modul ulasan"Output yang Dihasilkan (perintah terakhir):
src/ulasan.js:2: trailing whitespace.
+function tampilkanUlasan(daftar) {
pre-commit: whitespace error — lihat daftar di atasPerbaiki barisnya, lalu masukkan K5 — jejak debug di baris ketiga:
printf '// Modul ulasan pelanggan untuk web-toko.\nfunction tampilkanUlasan(daftar) {\n return daftar.slice(0, 10);\n}\n' > src/ulasan.js
git add src/ulasan.js
printf '// Modul ulasan pelanggan untuk web-toko.\nfunction tampilkanUlasan(daftar) {\n console.log("debug: daftar masuk");\n return daftar.slice(0, 10);\n}\n' > src/ulasan.js
git add src/ulasan.js
git commit -m "feat(ulasan): tambah modul ulasan"Output yang Dihasilkan (perintah terakhir):
3: console.log("debug: daftar masuk");
pre-commit: jejak debug di src/ulasan.js — hapus sebelum commitBersihkan kembali, lalu K6 — berkas besar ikut di-staging bersama modul yang sehat:
printf '// Modul ulasan pelanggan untuk web-toko.\nfunction tampilkanUlasan(daftar) {\n return daftar.slice(0, 10);\n}\n' > src/ulasan.js
git add src/ulasan.js
mkdir aset
python3 -c "open('aset/banner.bin','wb').write(b'\x89PNG' + bytes(1200000))"
git add aset/banner.bin
git commit -m "feat(ulasan): tambah modul ulasan"
git reset aset/banner.bin
rm -rf asetOutput yang Dihasilkan (perintah git commit):
pre-commit: aset/banner.bin (1200004 byte) melebihi 1 MiBBanner ditarik keluar dari staging area dan dihapus — aset besar diserahkan ke CDN. Terakhir, K7: commit dengan pesan dan isi yang sehat:
git commit -m "feat(ulasan): tambah modul ulasan"Output yang Dihasilkan:
[main d0e0183] feat(ulasan): tambah modul ulasan
1 file changed, 4 insertions(+)
create mode 100644 src/ulasan.jsHasil akhirnya cocok satu per satu dengan tabel: K1–K6 ditolak dengan alasan yang tepat, K7 lahir sebagai commit d0e0183. Tujuh dari tujuh — gerbang ini boleh dipercaya.
Pemasangan Tim: core.hooksPath #
Sampai titik ini pemasangan kita masih menyalin berkas ke .git/hooks/ — salinan yang tidak ikut di-clone dan berumur pendek. Git punya jalur yang lebih rapi sejak versi 2.9: konfigurasi core.hooksPath mengarahkan Git ke folder hook mana pun, termasuk folder hooks/ yang hidup di dalam repository. Siapkan dokumentasinya dulu agar rekan tim tahu ritualnya:
printf '# web-toko\n\nAplikasi toko web untuk latihan otomasi Git hooks — Course Git\nProyek 06.\n\n## Isi\n\n- `src/app.txt` — peta halaman aplikasi\n- `src/promo.txt` — halaman promo\n- `src/kupon.js` — modul kupon diskon\n- `src/ulasan.js` — modul ulasan pelanggan\n\n## Pemasangan Hooks\n\nRepository ini menjaga kualitas commit lewat hooks pada folder\nversioned `hooks/` dan `scripts/`. Setelah melakukan clone, jalankan\nsatu perintah:\n\n git config core.hooksPath hooks\n\nPesan commit mengikuti Conventional Commits — aturannya berada\ndi `scripts/validate-commit-message.sh`.\n' > README.md
cat README.md
git add README.mdOutput yang Dihasilkan (perintah cat README.md):
# web-toko
Aplikasi toko web untuk latihan otomasi Git hooks — Course Git
Proyek 06.
## Isi
- `src/app.txt` — peta halaman aplikasi
- `src/promo.txt` — halaman promo
- `src/kupon.js` — modul kupon diskon
- `src/ulasan.js` — modul ulasan pelanggan
## Pemasangan Hooks
Repository ini menjaga kualitas commit lewat hooks pada folder
versioned `hooks/` dan `scripts/`. Setelah melakukan clone, jalankan
satu perintah:
git config core.hooksPath hooks
Pesan commit mengikuti Conventional Commits — aturannya berada
di `scripts/validate-commit-message.sh`.Sekarang ujian yang membedakan core.hooksPath dari sekadar cp: hapus kedua salinan di .git/hooks/, pasang konfigurasinya, lalu buktikan hook tetap hidup:
rm .git/hooks/commit-msg .git/hooks/pre-commit
ls .git/hooks/commit-msg .git/hooks/pre-commit
git config core.hooksPath hooks
git config core.hooksPath
git commit -m "update"
git commit -m "docs: dokumentasikan pemasangan hooks"Output yang Dihasilkan (perintah ls .git/hooks/commit-msg .git/hooks/pre-commit):
ls: cannot access '.git/hooks/commit-msg': No such file or directory
ls: cannot access '.git/hooks/pre-commit': No such file or directoryOutput yang Dihasilkan (perintah git config core.hooksPath):
hooksOutput yang Dihasilkan (perintah git commit -m "update"):
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'Output yang Dihasilkan (perintah git commit -m "docs: …"):
[main f40f159] docs: dokumentasikan pemasangan hooks
1 file changed, 14 insertions(+)Rangkai buktinya: kedua salinan sudah tidak ada, git config core.hooksPath menjawab hooks, dan pesan "update" tetap ditolak. Git tidak lagi membaca .git/hooks/ — Git membaca folder hooks/ di dalam repository, folder yang sama yang ikut ter-clone dan ikut ter-review. Commit dokumentasi pun lahir, membawa riwayat ke sembilan:
git log --onelineOutput yang Dihasilkan:
f40f159 docs: dokumentasikan pemasangan hooks
d0e0183 feat(ulasan): tambah modul ulasan
1a1337c refactor: pisahkan validasi pesan ke skrip inti
6f7aed7 chore: pasang pemeriksaan pre-commit
3e08c4d feat: tambah kupon diskon
0f3e0f1 feat: tambah halaman promo
668d6c2 chore: pasang validasi pesan commit
9643466 feat: tambah keranjang
e9d7cc7 feat: rintis web-tokoClone Baru oleh Siti: Celah yang Terbukti #
Inilah momen kejujuran proyek: apa yang benar-benar diterima rekan baru? Simulasikan Siti yang meng-clone web-toko — keluar dari repository dulu:
cd ..
git clone web-toko web-toko-siti
cd web-toko-siti
git config user.name "Siti Rahma"
git config user.email "[email protected]"
git config core.hooksPath
ls .git/hooks/commit-msg .git/hooks/pre-commitOutput yang Dihasilkan (perintah git clone web-toko web-toko-siti):
Cloning into 'web-toko-siti'...
done.Perintah git config core.hooksPath pulang tanpa keluaran — dan dengan exit code 1, sinyal bahwa kunci itu belum ada di clone. Sementara itu dua hook juga tidak ada:
Output yang Dihasilkan (perintah ls .git/hooks/commit-msg .git/hooks/pre-commit):
ls: cannot access '.git/hooks/commit-msg': No such file or directory
ls: cannot access '.git/hooks/pre-commit': No such file or directoryFolder hooks/ dan scripts/ ada di clone — keduanya ikut ter-clone sebagai berkas biasa — tetapi tidak ada satu pun yang aktif. Siti belum tahu itu, dan seperti kebanyakan dari kita, ia langsung bekerja:
printf '\nModul ulasan dikelola oleh Siti Rahma.\n' >> README.md
git add README.md
git commit -m "update readme"Output yang Dihasilkan (perintah terakhir):
[main 79eb5e6] update readme
1 file changed, 2 insertions(+)Commit lahir — pesan tanpa type dan tanpa format lolos begitu saja. Inilah batas hooks sisi klien yang dibedah di Konsep Git Hooks
: pencegahan, bukan jaminan. Yang untung, commit ini masih lokal di clone Siti, belum terdorong ke mana pun.
Siti membaca README yang barusan di-commit Budi, lalu menjalankan satu-satunya perintah yang dimintanya:
git config core.hooksPath hooksPerintah itu senyap — exit code 0, tanpa keluaran. Dengan satu baris, Git di mesin Siti kini membaca folder hooks/ yang sejak awal sudah ada di clone-nya. Pesan commit buruknya bisa dibenahi lewat git commit --amend — dan amend menjalankan ulang kedua hook, jadi pesan buruk tidak bisa menyelundup balik:
git commit --amend -m "update"
git commit --amend -m "docs: dokumentasikan modul ulasan"Output yang Dihasilkan (perintah git commit --amend -m "update"):
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'Output yang Dihasilkan (perintah git commit --amend -m "docs: …"):
[main 2a4321a] docs: dokumentasikan modul ulasan
Date: Tue Dec 15 11:30:00 2026 +0700
1 file changed, 2 insertions(+)Pesan "update" ditolak di pintu yang sama; pesan yang benar lolos, dan baris Date: menunjukkan author date asli commit Siti tetap terjaga — perilaku amend yang dibahas di Amend Commit
. Riwayat di clone Siti kini sepuluh commit, dengan sembilan milik Budi yang dijaga penuh dan satu milik Siti yang sudah dibereskan:
git log --onelineOutput yang Dihasilkan:
2a4321a docs: dokumentasikan modul ulasan
f40f159 docs: dokumentasikan pemasangan hooks
d0e0183 feat(ulasan): tambah modul ulasan
1a1337c refactor: pisahkan validasi pesan ke skrip inti
6f7aed7 chore: pasang pemeriksaan pre-commit
3e08c4d feat: tambah kupon diskon
0f3e0f1 feat: tambah halaman promo
668d6c2 chore: pasang validasi pesan commit
9643466 feat: tambah keranjang
e9d7cc7 feat: rintis web-tokoStrategi Distribusi Hooks #
Pola yang barusan kita jalankan hanyalah satu dari beberapa cara menutup celah distribusi. Perbandingan lengkapnya pernah diuji nyata di Mengelola Hooks ; ringkasannya:
| Strategi | Satu langkah per clone | Mutakhir lewat git pull | Cocok untuk |
|---|---|---|---|
hooks/ + salin manual / install.sh | cp atau ./install.sh | salinan perlu dipasang ulang | repo pribadi, tim sangat kecil |
core.hooksPath ke folder versioned | git config core.hooksPath hooks | ya — folder ikut ter-clone | tim tanpa framework, Git ≥ 2.9 |
framework pre-commit | pre-commit install | ya — konfigurasi versioned | tim multi-bahasa, butuh hook siap pakai |
| template directory | tidak perlu (hanya git init) | tidak — salinan sekali jadi | standar proyek baru di satu mesin |
Web-toko memilih core.hooksPath karena paling sedikit bergerak: hooknya sudah di dalam repository, pemasangannya satu perintah, dan pembaruannya mengikuti git pull biasa. Lapisan penegakan berikutnya — yang tidak bisa dilewati siapa pun — berdiri di sisi server dan CI, dibahas di Git dalam CI/CD
.
Ringkasan Proyek #
Mesin penjaga yang dijanjikan penutup Proyek 05 kini berdiri dan teruji:
| Pencapaian | Bukti pada sesi |
|---|---|
| Menguasai mekanisme hook | commit ditolak nyata saat exit 0 dibalik jadi exit 1; staging area terbukti utuh |
| Validasi pesan Conventional Commits | "update" dan "perbaiki bug ulasan" ditolak dengan petunjuk; subjek 93 karakter ditolak; sembilan commit semuanya lolos pola |
| Pemeriksaan isi staging area | trailing whitespace, console.log, dan berkas 1.200.004 byte — masing-masing menolak commit secara nyata (K1–K7: tujuh dari tujuh) |
| Struktur yang bisa dipakai ulang | hooks/commit-msg menjadi pembungkus scripts/validate-commit-message.sh; penolakan tetap bekerja pasca-refaktor |
| Pemasangan lintas mesin | core.hooksPath aktif tanpa satu pun salinan; clone Siti membuktikan celah lalu pulih dengan satu perintah + --amend |
Konsep yang barusan dilatih tangan ini memiliki kedalaman teorinya masing-masing: mekanisme exit code di Konsep Git Hooks , format pesan di Conventional Commits , kedua hooknya di Pre-Commit Hook dan Commit-Msg Hook , serta strategi distribusinya di Mengelola Hooks .
Kompetensi tim web-toko kini lengkap pada satu siklus: menulis, meninjau, memulihkan, dan mencegah. Satu ritual terakhir belum pernah dijalankan secara utuh: membungkus pekerjaan yang sudah terjaga ini menjadi rilis bernomor — menentukan versi, menandai titik rilis dengan tag, menyusun changelog dari riwayat yang barusan kita jaga formatnya. Riwayat web-toko yang rapi itu modal sempurna untuk ritual tersebut: Proyek 07: Simulasi Release .
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