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:

Representasi secara horizontal

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

You are not alone

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

Cabang main/master sebagai "badan pohon"

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:

  1. Perubahan yang sedang kamu buat akan dipindahkan ke branch baru untuk melakukan hotfix tersebut
  2. 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:

Sudah jelas pesannya

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".

Contoh sederhana

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.

Hanya untuk konten

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"):

Ini contoh merge

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.

Mencoba untuk merge

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.

Contoh merge

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

Hasil merge

Mengapa disebut masalah?

  1. Commit history menjadi kurang rapih
  2. 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?

Contoh rebase

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.

Contoh hasil melakukan re-ordering untuk rentang history head~2

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
Keluaran dari git rebase head~2

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
Melakukan re-ordering commit history

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:

Contoh ngawur

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:

Masih contoh ngawur

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:

Contoh 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>:

Contoh penggunaan 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