VCS atau Video Call S... Version Control System sangat membantu pekerjaan kita dalam membuat dan mengembangkan program, khususnya ketika bekerja sama dengan tim.
Meskipun VCS/SCM tidak diajarkan di bangku perkuliahan, namun sayangnya penggunaan alat ini sangat krusial untuk para pemrogram karena benefit yang ditawarkan agar proses pengembangan program menjadi lebih efektif dan efisien.
Sebelumnya, jika kamu belum terlalu familiar dengan VCS/SCM, silahkan bisa baca buku digital ini yang dapat diakses secara gratis. Jika sudah familiar, bisa lanjut membaca tulisan ini.
Disini kita menggunakan git daripada alternatif (seperti Mercurial, Fossil, dkk) karena penggunaannya yang sudah mendominasi di industri peranti lunak.
Terlebih semakin populernya layanan-layanan untuk menyimpan repositori[1] di remote server seperti Sourcehut, GitHub, GitLab, Bitbucket, dsb yang mana tidak hanya memberikan layanan penyimpanan, melainkan infrastruktur lain yang mendukung dalam proses pembuatan & pengembangan peranti lunak atau program.
Oke sekarang kita mulai masuk ke pembahasan, program git menggunakan struktur data Hash/Merkle Tree, yang berarti, bisa di representasikan dengan pohon yang mana memiliki ranting/cabang.
Nah, pohon "idaman" di project yang menggunakan git itu kurang-lebih seperti ini:

Sayangnya terkadang kenyataan tidak selalu sesuai harapan, terkadang secara realistis yang terjadi adalah seperti ini:

Untuk menghindari kasus diatas—agar commit history tetap rapih—biasanya kita menggunakan pendekatan trunk dalam pengembangan kita:

Yang mana setiap perubahan yang terjadi selalu berasal dari cabang utama, dan akan kembali ke cabang tersebut.
Oke itu hanya gambaran singkat aja terkait pengembangan peranti lunak menggunakan git. Pengembang utama kernel dan git—yakni lord Linus—dalam mengembangkan kernel, prosesnya sampai hari ini hanya dia yang memiliki hak untuk menerapkan perubahan yang dibuat oleh pengembang lain, yang mana dengan cara mengirim berkas patch, lalu doi akan menentukan apakah perubahan tersebut akan diterapkan atau tidak.
Yang mana proses diatas biasa disebut dengan "Merge Request".
Tapi kita sedang tidak membahas tutorial menggunakan git, jadi, kembali ke topik pembahasan, disini kita akan membahas beberapa perintah yang cocok digunakan untuk pengembang yang sibuk.
...Dan pastinya yang menggunakan git dalam proses pengembangannya.
Jika kamu termasuk orang yang sibuk, mungkin tulisan ini cocok untuk kamu!
Stash
Ini yang paling sederhana.
Pernah mendapat kejadian ketika sedang mengembangkan fitur lain, namun mendapatkan "tugas negara" yang urgent seperti hotfix?
Ada 2 kemungkinan yang terjadi:
- Perubahan yang sedang kamu buat akan dipindahkan ke branch baru untuk melakukan hotfix tersebut
- Perubahan yang sedang kamu buat harus di commit terlebih dahulu karena versi yang ada di branch tersebut berbeda dengan yang ada di branch utamanya
Kira-kira begini gambarannya:

Jika kita melakukan commit, sayangnya fitur tersebut belum jadi. Mungkin bisa saja kita melakukan cp index.js /tmp; git checkout -- index.js
jadi ketika sudah selesai melakukan hotfix kita tinggal pindah ke branch yang sedang dikembangkan lalu tinggal pindahkan yang ada di /tmp
ke project direktori kita.
Itupun kalau ingat dan tidak terhapus hahaha.
Tapi ada cara yang lebih mudah, yaitu menggunakan git-stash(1)
.
Jika git-add
dan git-commit
memindahkan perubahan kita ke staging area, dengan git-stash
memindahkan perubahan tersebut ke "temporary area".

Berdasarkan contoh diatas, seharusnya berkas index.js
terdapat perubahan (berdasarkan yang terjadi di cabang fitur-baru
) sedangkan ketika pindah ke master
tidak ada!
Ketika sudah selesai menyelesaikan hotfix misalnya, kita bisa kembali lagi ke cabang fitur-baru
dan mengambil perubahan yang disimpan ke "temporary area" tersebut dengan git stash apply
.

Kamu juga bisa membuat "stash" lebih dari satu dan juga bisa diberi nama biar lebih deskriptif. Untuk mempelajari lebih lanjut tentang git-stash
, bisa membaca dokumentasi ini.
Rebase
Ini yang paling sering digunakan meskipun tidak hanya berlaku untuk orang yang sibuk.
Sebagai mana namanya, rebase berarti "meng-base ulang"—apaan sih anjink, skip.
Rebase intinya mengatur ulang struktur terkait perubahan yang ada, kita ambil contoh diatas (yang memiliki caption "Cabang main/master sebagai "badan pohon"):

Lalu kita membuat perubahan di branch baru dengan nama masih-fitur-baru
dan melakukan commit dengan pesan "feat: create forgot password page".
Ketika ingin di merge, ternyata ada konflik terkait history yang mana history yang ada di masih-fitur-baru
berbeda dengan master
.

Mengapa terjadi konflik? Karena head yang diketahui masih-fitur-baru
adalah feat: create login page
sedangkan yang ada di cabang target (untuk meminta merge) head nya adalah feat: create register page
.
Masalah ini masih mudah diatasi, dengan melakukan merge, kita membuat "commit baru" untuk membuat head baru.

Nah "commit baru" tadi biasa disebut dengan "merge commit". Sekilas seperti tidak ada masalah, sampai kita melihat "graph" yang ada di branch utama kita:

Mengapa disebut masalah?
- Commit history menjadi kurang rapih
- Pesan commit terlihat kurang kontekstual
Yaa masa kita buat si pesan commit Merge branch masih-fitur-baru
menjadi feat: register page + forgot password
yang meskipun terlihat baik-baik saja.
Nah dengan rebase, masalah ini bisa terselesaikan.
Karena dia akan "menyesuaikan" history yang ada, karena rebase pada dasarnya menulis ulang sejarah.
Dan ehm, bukankah sejarah ditulis oleh mereka yang menang?

Sekarang perubahan menjadi lebih rapih!
Bila dilihat dari git-log
nya, sepertinya urutannya ada yang salah, yang mana seharusnya register lebih awal daripada forgot password, dan sekali lagi, rebase adalah tentang menulis ulang sejarah, jadi, mari kita buat urutannya menjadi yang paling benar menurut kita.

Caranya ehm, sederhana, tinggal rebase commit mana aja yang ingin ditulis ulang sejarahnya, lalu yaudah deh HAHAHA. Oke oke, mengambil contoh diatas, ketika melakukan perintah git rebase HEAD~2
, maka editor akan membuka sebuah berkas yang berisi seperti ini kurang lebih:
pick c1a18b5 feat: create forgot password page
pick 2163a1b feat: create register page
# Rebase bf0321a..c1a18b5 onto bf0321a (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
Nah tinggal pindahkan si c1a18b5
ke sesudah 2163a1b
, lalu simpan, maka commit history akan berubah ke yang ingin kamu ubah:
pick 2163a1b feat: create register page
pick c1a18b5 feat: create forgot password page
Dan ketika disimpan, maka kurang lebih hasilnya akan sama dengan tangkapan layar yang sudah disisipkan diatas!
Rebase cocok untuk yang bekerja secara paralel dengan anggota tim yang bergerak dengan sangat cepat. Karena dengan melakukan rebase, kita bisa melakukan hal-hal lain terkait commit history seperti reword/ammend, re-ordering, squash, dsb.
Yang sederhananya, jika kamu ingin melakukan perubahan terkait commit history, harusnya git-rebase(1)
yang melakukan itu.
Perlu di ingat, git-rebase
adalah tentang menulis ulang sejarah. Maka dari itu harap dilakuan dengan teliti dan hati-hati untuk mengurangi kemungkinan terjadinya konflik yang fatal seperti hilangnya perubahan yang dilakukan oleh temanmu
Karena sudah lama menjadi IC—dan semenjak bekerja sebagai tukang ketik di salah satu perusahaan pengembang platform data (Yes, they're still hiring)—jadi mau tidak mau harus mengingat ulang cara melakukan rebase karena kembali bekerja sama dengan tim.
Dan agar proses mengingat ulang ini ter-dokumentasi, itulah mengapa tulisan ini ada. Hahaha.
Untuk mempelajari lebih lanjut tentang git-rebase, bisa baca dokumentasi ini.
Cherry pick
Sejujurnya belum pernah menggunakan ini di kerjaan, tapi setelah mendapat insight dari manajer gue pas jumat kemarin, baru mendapatkan beberapa kasus yang sekiranya cocok dengan pengguna cherry pick.
Ingat kan proses "hotfix" diatas yang terlihat sangat mudah?
Tapi harapan terkadang tidak sesuai dengan realita, terlebih ketika bekerja bersama dengan tim.
Oke kembali ke pembahasan, pernahkah kamu mendapatkan kondisi seperti "Eh bug itu udah fixed di PR X" atau "Ternyata gw salah branch pas commit lol" yang intinya membuat sebuah perubahan di tempat yang bukan seharusnya.
Nah, git-cherry-pick(1)
bisa menyelesaikan masalah tersebut yang mana dia dapat menerapkan commit dari branch satu ke branch lain.
Sekarang mari kita ambil contoh:

Anggap kode diatas adalah sebuah critical bug yang ingin kita ubah yang mana kita sedang berada di branch wee
.
Lalu di branch hot
seseorang (panggil aja adrin) mengetahui bug tersebut dan membuat perubahan (baca: fix bug) terhadap bug tersebut:

Anggap bug tersebut di resolve nya dengan mengubah isinya menjadi "OK now what?"
. Dan jika melihat melihat perubahan yang berada di cabang hot
yang sedang adrin kerjakan, ada lebih dari satu perubahan:

Sedangkan yang kita inginkan hanyalah commit dari 97f9546
, karena jika kita rebase ataupun merge, commit 0a8d386
pun akan terbawa.
Nah karena kita sudah membahas sedikit tentang git-cherry-pick, kita bisa mengambil commit tersebut dengan perintah git cherry-pick <sha_id>
:

git cherry-pick 97f9546
Yang mana sekarang perubahan tersebut sudah diterapkan!
Namun perlu diingat, perintah cherry pick membuat commit baru yang singkatnya, history (terkait hotfix tersebut) yang ada di cabang wee
berbeda dengan yang ada di cabang hot
, yang satu memiliki sha id 97f9546
(hot) dan yang satu adalah 86db5c0
(wee).
Jadi, pasti akan ada konflik.
Namun hotfix biasanya terjadi terhadap suatu tag yang dianggap sebagai "rilis" jadi seharusnya tidak mempengaruhi perubahan lain yang ada mengingat rilis bersifat immutable[2].
Penutup
Kita sudah mengenal beberapa perintah git yang sepertinya berguna untuk orang-orang yang sibuk at work, yang sering berpindah-pindah ketika mengembangkan sebuah fitur, dan yang suka ceroboh seperti penulis huhuhu.
Tulisan ini adalah awal dari bagian Tooling yang mana khusus membahas tentang program-program yang dapat membantu workflow kita menjadi lebih efektif dan efisien lagi.
Jika terdapat kesalahan konsep, typo, ataupun pertanyaan bisa mention kita di Twitter, terima kasih dan selamat bekerja!
[1]: Repositori adalah sebuah kumpulan berkas yang menampung berbagai versi yang beda terhadap sebuah projek
[2]: Syarat dan ketentuan berlaku, termasuk karena kasus diatas