Tag v1.0.0 di chapter sebelumnya memakai angka tanpa ditanya asalnya. Padahal angka itulah bahasa yang dibaca pengguna: 0.1.0 berarti “coba saja”, 1.0.0 berarti “sudah bisa diandalkan”, 2.0.0 berarti “siap-siap menyesuaikan kode”. Tanpa aturan bersama, angka versi cuma selera — proyek A melompat ke 2.0 karena tambah fitur, proyek B karena mengganti logo. Semantic Versioning (SemVer) menstandarkan makna angka sehingga penomoran bisa dibaca mesin dan manusia. Chapter ini menerapkan aturannya pada riwayat tag proyek kasir kecil, termasuk fase pra-rilis dan jebakan urutannya di Git.

Anatomi MAJOR.MINOR.PATCH #

SemVer menomori versi dengan tiga angka:

SegmenNamaKapan dinaikkan
1MAJORperubahan yang merusak kompatibilitas — pemakai versi lama harus menyesuaikan
2MINORfitur baru yang mundur-kompatibel — pemakai lama tidak apa-apa, ada bonus
3PATCHperbaikan bug yang mundur-kompatibel — perilaku salah dibetulkan

Aturan penaikannya bertingkat seperti odometer: perbaikan bug menaikkan PATCH; fitur baru mereset PATCH dan menaikkan MINOR; perubahan merusak mereset keduanya dan menaikkan MAJOR. Contoh nyatanya: memperbaiki salah hitung kembalian di kasir berarti 1.2.0 → 1.2.1; menambah mode diskon member berarti 1.2.1 → 1.3.0; mengubah format struk yang memaksa pelanggan mengganti parser mereka berarti 1.3.0 → 2.0.0.

Riwayat Versi Sebuah Proyek Kecil #

Aturan itu paling jelas dilihat sebagai riwayat sungguhan. Kita bangun layar kasir sederhana dan menomori setiap titiknya dengan tag — pra-rilis menyala di tengah jalan, lalu stabilisasi dan perubahan besar menutupnya:

bash
mkdir latihan-semver && cd latihan-semver
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 "Buat layar kasir dasar"
git tag 0.1.0
printf 'total belanja: 0\ndiskon member: 10 persen\n' > kasir.md
git add kasir.md
git commit -m "Tambah hitung diskon member"
git tag 0.2.0
printf 'total belanja: 0\ndiskon member: 10 persen\nkembalian dihitung dari total\n' > kasir.md
git add kasir.md
git commit -m "Perbaiki salah hitung kembalian"
git tag 0.2.1
printf 'total belanja: 0\ndiskon member: 10 persen\nkembalian dihitung dari total\nstruk: siap\n' > kasir.md
git add kasir.md
git commit -m "Susun kandidat alpha tampilan struk"
git tag 1.0.0-alpha
printf 'total belanja: 0\ndiskon member: 10 persen\nkembalian dihitung dari total\nstruk: rapi\n' > kasir.md
git add kasir.md
git commit -m "Rapikan tampilan diskon untuk beta"
git tag 1.0.0-beta
printf 'total belanja: 0\ndiskon member: 10 persen\nkembalian dihitung dari total\nstruk: final\n' > kasir.md
git add kasir.md
git commit -m "Kandidat rilis akhir 1.0.0"
git tag 1.0.0-rc.1
printf '# Kasir Toko\ntotal belanja: 0\ndiskon member: 10 persen\nkembalian: otomatis\nstruk: final\n' > kasir.md
git add kasir.md
git commit -m "Rilis stabil 1.0.0"
git tag 1.0.0
printf '# Kasir Toku\ntotal: 0\ndiskon: 10%%\nkembalian: otomatis\nstruk: final\n' > kasir.md
git add kasir.md
git commit -m "Ubah format struk tidak kompatibel"
git tag 2.0.0

Delapan commit, delapan tag. Riwayat lengkapnya terbaca sekali jalan:

bash
git log --oneline --decorate

Output yang Dihasilkan:

text
67a02cf (HEAD -> main, tag: 2.0.0) Ubah format struk tidak kompatibel
692f611 (tag: 1.0.0) Rilis stabil 1.0.0
69368bd (tag: 1.0.0-rc.1) Kandidat rilis akhir 1.0.0
386dd7d (tag: 1.0.0-beta) Rapikan tampilan diskon untuk beta
3dff346 (tag: 1.0.0-alpha) Susun kandidat alpha tampilan struk
9692108 (tag: 0.2.1) Perbaiki salah hitung kembalian
e9c7763 (tag: 0.2.0) Tambah hitung diskon member
3fb4fb6 (tag: 0.1.0) Buat layar kasir dasar

Alasan setiap loncatannya diringkas berikut — persis narasi yang tidak bisa ditulis ulang dari angka saja:

LoncatanSegmen naikAlasan
0.1.0 → 0.2.0MINORfitur baru: hitung diskon member
0.2.0 → 0.2.1PATCHperbaikan bug: salah hitung kembalian
0.2.1 → 1.0.0MAJORdeklarasi stabil: kontrak publik ditetapkan
1.0.0 → 2.0.0MAJORformat struk berubah, kompatibilitas rusak

Fase 0.x: Masih Mencari Bentuk #

Versi 0.1.0 sampai 0.2.1 sengaja belum menyentuh 1.0.0. SemVer menyebut fase awal ini khusus: selama MAJOR bernilai 0, apapun boleh berubah kapan pun — penomoran 0.x adalah pengumuman “jangan bergantung pada saya dulu”. Naik dari 0.x ke 1.0.0 bukan fitur baru, melainkan komitmen: mulai titik itu setiap perubahan merusak akan dibayar kenaikan MAJOR, dan pengguna berhak protes bila janji itu dilanggar. Karena itu rilis 1.0.0 biasanya menyertai peristiwa stabil — API dibekukan, dokumentasi tuntas, atau pengguna pertama di luar tim.

Fase Pra-rilis: alpha, beta, rc #

Tiga tag di tengah riwayat tadi — 1.0.0-alpha, 1.0.0-beta, 1.0.0-rc.1 — adalah penanda pra-rilis: alpha (fungsi inti baru jadi), beta (siap diuji orang luar), rc (release candidate — kandidat final menunggu persetujuan). SemVer menetapkan urutan naik: alpha dulu, lalu beta, lalu rc, dan versi final berdiri paling akhir — pra-rilis selalu lebih rendah dari rilisnya. Mari saring daftar tag pada keluarga 1.0.0:

bash
git tag -l "1.0.0*"

Output yang Dihasilkan:

text
1.0.0
1.0.0-alpha
1.0.0-beta
1.0.0-rc.1

Ada yang aneh pada urutan itu: 1.0.0 berdiri sebelum 1.0.0-alpha. Keluaran git tag diurutkan secara alfabetis, dan string yang habis (1.0.0) menang atas yang berlanjut (1.0.0-alpha). Untuk urutan versi yang benar, kita minta Git mengurutkan sebagai versi dengan trik versionsort.suffix:

bash
git -c versionsort.suffix=- tag --sort=v:refname -l "1.0.0*"

Output yang Dihasilkan:

text
1.0.0-alpha
1.0.0-beta
1.0.0-rc.1
1.0.0

Urutan kini sesuai SemVer: alpha → beta → rc.1 → final. Opsi versionsort.suffix=- memberi tahu pengurutan bahwa tanda minus menandai akhiran pra-rilis sehingga 1.0.0-alpha diperlakukan lebih rendah daripada 1.0.0. Tanpa konfigurasi itu pengurutan versi Git menempatkan pra-rilis setelah versi finalnya — jebakan yang kerap mengagetkan saat skrip otomatis memilih “versi terbaru”.

Daftar seluruh tag proyek ini memperlihatkan peta lengkapnya:

bash
git tag

Output yang Dihasilkan:

text
0.1.0
0.2.0
0.2.1
1.0.0
1.0.0-alpha
1.0.0-beta
1.0.0-rc.1
2.0.0

Konvensi v pada Nama Tag #

Dua gaya hidup berdampingan: tag 1.0.0 polos atau v1.0.0 berawalan v. SemVer sendiri tidak mengatur awalan — spesifikasinya membicarakan string versi 1.0.0, bukan nama ref. Praktiknya berbagi selera:

Kegunaanv-prefixtanpa v
Dibaca manusiajelas menyatakan “versi”ringkas, murni angka
Dibaca skrip dari berkas VERSIONperlu dikupas dulu (v dibuang)langsung terpakai
Kebiasaan ekosistemGit sendiri, banyak proyek C/Gobanyak proyek Ruby/Rust

Yang menentukan bukan rasa, melainkan konsistensi: campur v1.0.0 dengan 2.0.0, dan pola git tag -l "v1.*" akan kehilangan separuh riwayat. Pilih satu gaya di awal proyek, catat di pedoman kontribusi, dan pertahankan. Materi section ini memakai v pada repo yang meniru rilis publik, dan polos pada latihan SemVer murni — agar keduanya terasa sama-sama wajar.

Penomoran yang disiplin barulah separuh alur rilis. Setelah tahu angka apa yang akan dipakai, tinggal menjalankan rangkaian langkah terstandar dari pembekuan fitur sampai pengumuman — rangkaian itulah yang dirakit di chapter berikutnya: Release Workflow .