Siklus fitur di chapter sebelumnya tenang karena satu hal: tidak ada yang menderita sambil menunggu. Bug produksi membalik keadaannya — pelanggan melihat galat sekarang, dan menunggu branch fitur berikutnya selesai adalah jawaban yang salah. Tetapi “cepat” tanpa pola punya dua tagihan: riwayat kacau karena commit darurat tercecer, dan — lebih licik — perbaikan yang berangkat dari titik salah membawa setengah fitur belum selesai ikut terkirim ke produksi. Workflow hotfix menjawab keduanya: jalur pendek yang tetap tertib, berangkat dari titik yang persis sama dengan yang berjalan di produksi.

Pola: Branch dari Tag, Bukan dari main #

Inti polanya satu keputusan penempatan: branch hotfix/<id> dibuat dari tag rilis yang berjalan di produksi, bukan dari ujung main. Tag v1.2.0 menandai commit yang persis sama dengan kode yang dideploy — tidak kurang, tidak lebih. Ujung main bisa sudah berisi pekerjaan sesudah rilis: fitur setengah jadi, refactor yang belum teruji. Hotfix yang berangkat dari main membawa seluruh muatan itu ikut terkirim — menambal satu lubang sambil membuka lubang baru.

GitFlow menuntun aturan yang sama dari arah berbeda: di sana main hanya bergerak saat rilis sehingga ujungnya selalu sama dengan tag terakhir, dan hotfix dilarang berangkat dari develop yang penuh pekerjaan belum teruji. Pada repo yang commit langsung ke main, ujung main dan tag rilis bisa berjauhan — branch dari tag adalah jaminan bahwa basis perbaikan adalah produksi apa adanya. Praktik merawat rilis dan menerima perbaikan semacam ini di proyek nyata diringkas Pro Git di bab menjaga proyek .

Sesi Nyata: Bug Kembalian di v1.2.0 #

Aplikasi kasir baru saja dirilis. Versi produksi ditandai tag annotated:

bash
mkdir kasir && cd kasir
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf 'total belanja: 0\n' > kasir.md
git add kasir.md
git commit -m "Rilis kasir 1.2.0"
git tag -a v1.2.0 -m "Rilis 1.2.0"

Output yang Dihasilkan (git commit):

text
[main (root-commit) d88a668] Rilis kasir 1.2.0
 1 file changed, 1 insertion(+)
 create mode 100644 kasir.md

Hari berikutnya hidup berjalan normal — pekerjaan versi berikutnya masuk ke main, sementara develop menampung fitur diskon:

bash
printf '# Laporan\n\n(dikerjakan)\n' > laporan.md
git add laporan.md
git commit -m "Mulai laporan penjualan"
git switch -c develop
printf '# Diskon\n\n(dikerjakan)\n' > diskon.md
git add diskon.md
git commit -m "Mulai fitur diskon"
git switch main
git log --oneline --decorate -3

Output yang Dihasilkan (perintah terakhir):

text
eecb31b (HEAD -> main) Mulai laporan penjualan
d88a668 (tag: v1.2.0) Rilis kasir 1.2.0

Laporan penjualan yang belum selesai itu belum teruji — dan di sinilah bug melanda: pelanggan melaporkan layar kasir tidak pernah menampilkan baris kembalian. Dari output di atas, main sudah meninggalkan v1.2.0. Perbaikan harus berangkat dari tag:

bash
git switch -c hotfix/kembalian v1.2.0
git log --oneline -1

Output yang Dihasilkan:

text
Switched to a new branch 'hotfix/kembalian'
text
d88a668 Rilis kasir 1.2.0

Bukti letak basisnya terbaca langsung: satu-satunya commit di branch ini adalah d88a668 — commit bertanda v1.2.0, bukan eecb31b yang membawa laporan setengah jadi. Perbaikannya sendiri dibuat seminimal mungkin, lalu diuji sebelum ditandai:

bash
printf 'total belanja: 0\nkembalian: 0\n' > kasir.md
cat kasir.md
git add kasir.md
git commit -m "Perbaiki hitung kembalian"
git tag -a v1.2.1 -m "Rilis 1.2.1"

Output yang Dihasilkan (cat kasir.md dan git commit):

text
total belanja: 0
kembalian: 0
text
[hotfix/kembalian 1e23636] Perbaiki hitung kembalian
 1 file changed, 1 insertion(+)

Baris kembalian: 0 kini hadir — satu baris, satu masalah, selesai. Tag v1.2.1 mengikuti aturan SemVer: perbaikan bug yang mundur-kompatibel menaikkan angka PATCH, penalaran lengkapnya di Semantic Versioning . Penutup siklusnya dua merge balik — perbaikan harus pulang ke semua jalur yang hidup:

bash
git switch main
git merge --no-ff hotfix/kembalian -m "Gabungkan hotfix kembalian"
git switch develop
git merge --no-ff hotfix/kembalian -m "Gabungkan hotfix kembalian ke develop"
git branch -d hotfix/kembalian

Output yang Dihasilkan (merge ke main dan merge ke develop):

text
Merge made by the 'ort' strategy.
 kasir.md | 1 +
 1 file changed, 1 insertion(+)
text
Merge made by the 'ort' strategy.
 kasir.md | 1 +
 1 file changed, 1 insertion(+)

Mengapa balik ke develop juga? Tanpa merge itu, fitur diskon akan lahir dari dasar yang masih memuat bug. Peta akhirnya:

bash
git log --oneline --graph --all --decorate
git tag

Output yang Dihasilkan (dua perintah):

text
*   8741f81 (HEAD -> develop) Gabungkan hotfix kembalian ke develop
|\  
* | 726e5d8 Mulai fitur diskon
| | * 062e0fd (main) Gabungkan hotfix kembalian
| |/| 
|/|/  
| * 1e23636 (tag: v1.2.1) Perbaiki hitung kembalian
* | eecb31b Mulai laporan penjualan
|/  
* d88a668 (tag: v1.2.0) Rilis kasir 1.2.0
text
v1.2.0
v1.2.1

Hash di mesin pembaca berbeda, bentuknya tidak: dari v1.2.0, jalur main (kiri) menerima gelembung hotfix, jalur develop (atas) menerima gelembung yang sama — keduanya kini memuat 1e23636. Produksi memperoleh perbaikan lewat tag v1.2.1; pengirimannya tinggal git push origin main --tags, perilaku push tag dibahas di Berbagi Tag ke Remote .

Urgensi Menentukan Jalur #

Tidak semua galat berhak menaiki jalur hotfix. Tabel ini memilahnya:

SituasiJalurAlasan
Galat pada fitur yang belum diriliscommit perbaikan biasa di branch fiturbelum ada pengguna yang menderita
Galat ditemukan di main sebelum rilis berikutnyafix biasa lewat branch pendek + reviewakan ikut terkirim pada rilis terjadwal
Galat yang berjalan di produksi (versi ter-tag)hotfix dari tag, tag patch, merge balikpengguna menderita sekarang; basis harus persis produksi
Perilaku salah tapi penyebab belum dipahamigit revert dulu, analisis kemudianmemulihkan produksi tanpa menunggu diagnosis — lihat Revert

Checklist Hotfix #

Saat alarm berbunyi, urutan ini bisa dijalankan hampir tanpa berpikir:

  1. Reproduksi dulu — galat yang tidak bisa direproduksi tidak bisa dibuktikan sembuh.
  2. Branch dari tag rilis — git switch -c hotfix/<id> v<x.y.z>, bukan dari main.
  3. Perbaikan minimal — satu masalah, satu perubahan terkecil yang menutupnya.
  4. Uji sebelum tag — bukti perilaku benar direproduksi juga di branch hotfix.
  5. Tag patch — naikkan PATCH saja (v1.2.0 → v1.2.1), jangan mencuri momen rilis MINOR.
  6. Merge balik ke semua jalur hidup — main dan develop bila ada.
  7. Push semuanya — branch main, branch develop, dan --tags.

Hotfix menutup lubang yang tidak direncanakan. Kebalikannya — lubang yang direncanakan dari awal — adalah rilis: kumpulan fitur yang dibekukan, distabilkan, ditandai, dan diumumkan lewat alur terulang tanpa drama. Workflow release, chapter berikutnya, merakit alurnya dari bahan-bahan yang kini sudah semuanya ada.