Mengelola Kode Program Dengan Git


Version control system (VCS) memungkinkan developer untuk ‘kembali ke masa lalu‘ melihat kembali kode program yang telah dimodifikasi.   Fitur ini sangat bermanfaat.   Saking bermanfaatnya,  saya selalu meletakkan seluruh file yang berkaitan dengan proyek ke dalam VCS: mulai dari diagram UML, skema database, data SQL untuk migrasi program lama, bahkan hingga file Photoshop untuk splash screen.   Yup, siapa tahu pengguna tidak senang dengan rancangan saat ini dan tiba-tiba ingin memakai rancangan splash screen minggu lalu ;)   Tanpa VCS, isi file minggu lalu (yang telah berubah) sudah lenyap!

Git adalah sebuah distributed version control system (DVCS).   Makna ‘distributed‘ disini berarti masing-masing developer bisa bekerja secara offline tanpa harus selalu terkoneksi ke sebuah server pusat.   Bahkan untuk memakai Git, bisa saja tanpa sebuah server pusat.   Sebagai ilustrasi, dua orang developer fiktif,  Edi dan Bram,  sedang mengembangkan sebuah proyek secara bersamaan.   Mereka akan bekerja di rumahnya masing-masing.   Edi membuat sebuah Git repository yang mewakili proyek tersebut di USB flash disk dengan perintah berikut ini:

$ git init --bare proyekBadai
Initialized empty Git repository in F:/proyekBadai/

Perintah di atas akan membuat sebuah bare repository yang hanya dipakai untuk melakukan sinkronisasi antara pekerjaan Edi dan Bram nantinya.

Di komputer Edi, berbekal dengan flash disk yang mengandung bare repository tersebut, ia akan melakukan men-kloning repository tersebut dengan memberikan perintah berikut ini:

$ cd ~/Desktop
$ git clone file://F:/proyekBadai

Sekarang, di folder ~/Desktop akan ada sebuah folder proyekBadai yang merupakan kloningan dari yang ada di flash disk.   Edi hanya perlu meletakkan kode programnya di folder komputer tersebut, dan bukan di bare repository di flash disk.

Bram kemudian meminjam flash disk berisi bare repository tersebut, dan memberikan perintah yang sama untuk membuat kloning dari bare repository yang ada di flash disk ke desktop-nya.

Kedua developer tersebut kemudian bekerja di komputer masing-masing.   Sebagai contoh, ini adalah simulasi pekerjaan yang dilakukan oleh Edi di repository miliknya:

$ echo 'Menu 1' >> menu.txt
$ echo 'Isi modul 1' >> modul1.txt
$ git add .
$ git commit -m 'Membuat modul 1'

Edi membuat dua file dengan nama menu.txt dan modul1.txt.   Anggap saja ini adalah kode program😉

Pada saat yang bersamaan, Bram juga menambahkan file pada repository miliknya:

$ echo 'Menu 2' >> menu.txt
$ echo 'Isi modul 2' >> modul2.txt
$ git add .
$ git commit -m 'Membuat modul 2'

Setelah semuanya selesai, Bram men-push perubahan yang dilakukannya ke upstream di flash disk.   Ia memberikan perintah berikut ini:

$ git push origin master

Sekarang, commit dengan pesan ‘Membuat modul 2’ milik Bram sudah dipindahkan ke upstream di flash disk.   Untuk memastikannya, ia berpindah ke folder di flash disk, dan memberikan perintah berikut ini:

$ cd F:/proyekBadai
$ git show-branch
[master] Membuat modul 2

Tugas Bram sudah selesai,  ia kemudian menyerahkan flash disk yang berisi bare repository ke Edi.   Kebetulan Edi juga telah selesai mengerjakan modul 1, sehingga ia berniat men-push perubahannya ke upstream.   Akan tetapi Edi akan memperoleh pesan kesalahan seperti berikut ini:

$ git push origin master
To file://F:/proyekBadai
 ! [reject]       master -> master (fetch first)
error: failed to push some refs to 'file://F:/proyekBadai'

Pesan kesalahan ini muncul karena pada saat Edi mengerjakan modul 1,  Bram telah duluan men-push kode programnya ke upstream di flash disk.   Agar bisa men-push ke upstream, Edi perlu terlebih dahulu mengambil perubahan yang dibuat oleh Bram di upstream dan men-merge perubahan tersebut dengan perubahan miliknya.   Edi memberikan perintah berikut ini:

$ git pull
...
Auto-merging menu.txt
CONFLICT (add/add): Merge conflict in menu.txt
Automatic merge failed; fix conflicts and then commit the result.

Git biasanya cukup pintar dalam melakukan merging file yang konflik.   Tapi pada kasus ini, baik Edi dan Bram sama-sama menambah item baru pada baris pertama, sehingga Git tidak tahu mana yang harus dipakai.   Edi perlu memperbaiki konflik ini dengan mengubah file menu.txt secara manual menjadi seperti berikut ini:

Menu 1
Menu 2

Setelah itu, Edi akan men-commit perubahan ini dengan memberikan perintah berikut ini:

$ git add menu.txt
$ git commit -m 'Menyesuaikan dengan perubahan dari Bram'

Sekarang, Edi akan memiliki 3 file, yaitu menu.txt, modul1.txt dan modul2.txt.   Ini mewakili hasil akhir yang diharapkan.   Untuk melihat riwayat perubahan, Edi dapat memberikan perintah berikut ini:

$ git log
commit 8ce2a6bdc83387c2f81c56d60e06fa0ce62a3df8
Merge: 1bcc42b 841b46d
Author: Edi <edi@dev.com>
Date:   Fri Apr 12 06:19:25 2013 +0700

    Menyesuaikan dengan perubahan dari Bram

commit 841b46d0dea229f55fd215e9cfadcd58b8aa64c2
Author: Bram <bram@dev.com>
Date:   Fri Apr 11 05:57:37 2013 +0700

    Membuat modul 2

commit 1bcc42b2346b95830bd6b3363425a9c8fa3a92f4
Author: Edi <edi@dev.com>
Date:   Fri Apr 10 05:56:45 2013 +0700

    Membuat modul 1

Saat ini perubahan masih ada di repository lokal milik Edi.   Untuk memindahkan perubahan ke upstream yang ada di flash disk, Edi memberikan perintah berikut ini:

$ git push

Oke, Edi kemudian meninggalkan komputer dan menikmati hidupnya untuk sejenak.

Kita kembali lagi ke Bram.  Saat ini Bram hanya memiliki kode program modul 2 dan tidak memiliki kode program modul 1 yang dibuat Edi. Bram juga ingin memperoleh kode program terbaru!  Ia meminjam flash disk yang berisi bare repository, mencolokkannya di komputer rumahnya, lalu Bram memberikan perintah berikut ini:

$ git pull
...
Updating 841b46d..8ce2a6b
Fast-forward
 menu.txt   | 1 +
 modul1.txt | 1 +
 2 files changed, 2 insertions(+)
 create mode 100644 modul1.txt

Kali ini tidak ada konflik saat melakukan pull dari upstream.   Hal ini karena Edi sudah menyelesaikan (atau mengatasi) konflik tersebut sebelumnya.   Sampai pada tahap ini, isi repository Bram akan sama persis dengan milik Edi (terdiri atas 3 file yaitu menu.txt, modul1.txt dan modul2.txt).

Pada contoh ini, Bram dan Edi memakai bare repository yang disimpan di sebuah flash disk sebagai perantara.   Hal ini bukanlah sesuatu yang efisien terutama bila mereka dipisahkan oleh jarak yang jauh.   Bila komputer mereka sama-sama terkoneksi ke internet, mereka dapat men-setup sebuah server Git sebagai upstream.   Selain mendukung protokol git (native), Git juga mendukung protokol lainnya seperti HTTP, HTTPS, SSH, dan SCP.   Sebuah server Git paling mudah dikonfigurasi bila memakai sistem operasi Linux.   Bila tidak ingin repot-report men-setup server sendiri, Bram dan Edit dapat layanan dari pihak penyedia server seperti GitHub.

Anggap saja Edi berubah pikiran dan tidak ingin menggunakan USB flash disk sebagai perantara;  ia kini ingin menggunakan sebuah PC bekas sebagai server (upstream).   Salah satu solusi yang disarankan untuk berbagi repository Git adalah melalui SSH.   Sebagai percobaan, Edi akan memakai Kali Linux.   Distro ‘live USB’ tersebut sudah dilengkapi dengan OpenSSH dan Git.   Saya tidak akan menyarankan penggunaan distro ini untuk keperluan nyata (dilihat dari sisi keamanan), tapi Edi hanya ingin sekedar mencoba😉

Ia mulai dengan mengaktifkan SSH daemon dan mengubah password root seperti berikut ini:

$ service ssh start
$ passwd

Lalu, ia membuat sebuah repository Git baru:

$ cd /
$ mkdir proyek
$ cd proyek
$ git init --bare proyekBadai

Setelah itu, Edi kembali ke laptopnya yang telah terhubung ke server Linux ini.   Dari laptopnya, ia menjalankan Git Bash di Windows dan memberikan perintah berikut ini:

$ cd ~/Desktop/proyekBadai
$ git push ssh://root@10.20.30.40/proyek/proyekBadai master

Pada perintah di atas, 10.20.30.40 adalah IP server upstream.   Bila IP terdaftar dalam DNS atau DDNS, maka Edi dapat menggunakan nama domain yang lebih mudah diingat.   Sampai disini, isi proyekBadai yang ada di upstream akan sama persis seperti dengan isi proyekBadai di repository lokal di laptop Edi.   Akan tetapi origin masih tetap merujuk pada repository yang ada di USB flash drive.   Sebagai buktinya, Edi memberikan perintah ini:

$ git remote show origin

Untuk menghapus dan mendefinisikan remote repository baru, Edi memberikan perintah berikut ini:

$ git remote remove origin
$ git remote add origin ssh://root@10.20.30.40/proyek/proyekBadai
$ git branch --set-upstream-to=origin/master master

Sekarang giliran Bram yang melakukan pengaturan agar repository di komputernya merujuk pada server milik Edi.   Bram memberikan perintah berikut ini:

$ git remote set-url origin ssh://root@10.20.30.40/proyek/proyekBadai
$ git pull

Sekarang, Edi dan Bram tidak perlu lagi bertukar USB flash disk.   Mereka dapat memanfaat koneksi internet mereka ke server Linux. Mereka tetap membuat kode program di komputer masing-masing, kemudian men-commit perubahan tanpa terhubung ke upstream, kembali melakukan perubahan kode program lagi, lalu men-commit perubahan, dan seterusnya.   Pada suatu saat (tidak sering), mereka terkoneksi ke server Linux dan men-push perubahan ke upstream.

Walaupun Edi dan Bram men-setup sebuah server, Git tetap adalah sebuah distributed VCS tanpa sebuah ‘pusat‘.   Peran server hanya sebagai koordinator.   Edi dan Bram tetap bekerja pada repository yang ada di komputer masing-masing.   Mereka masih bisa melakukan operasi Git seperti melihat riwayat file, melakukan commit, dan mengembalikan file ke versi lama tanpa harus selalu terhubung ke upstream.

Selain berkomunikasi melalui sharing file dan server, Git mendukung satu jenis kolaborasi lagi, yaitu melalui patch file yang dapat dikirim melalui email.   Anggap saja Edi adalah pihak yang bertanggung jawab mengelola kode program.   Pada skenario ini, Bram tidak dapat men-push perubahan secara langsung ke upstream.  Sebagai gantinya, ia dapat mengirimkan file patch ke Edi melalui email.   Nantinya, Edi akan melakukan review apakah perubahan yang dilakukan oleh Bram layak diterapkan atau tidak.

Sebagai contoh, Bram membuat modul 3 seperti pada berikut ini:

$ echo 'Isi modul 3' >> modul3.txt
$ git add modul3.txt
$ git commit -m 'Membuat modul 3'

Git dapat mengirim patch file secara langsung dengan perintah git send-email, tapi pada contoh ini,  Bram akan mengirim patch file dalam bentuk email attachment kepada Edi.   Ia memberikan perintah berikut ini untuk menghasil patch file berdasarkan commit terakhir:

$ git format-patch -1

Hasilnya adalah sebuah file dengan nama 0001-Membuat-Modul-3.patch.   File ini dikirim sebagai email kepada Edi dalam bentuk pesan teks (tanpa perubahan isi baik spasi maupun perubahan baris).

Edi yang menerima email segera men-copy file tersebut ke repository di komputernya.   Lalu ia memberikan perintah berikut ini:

$ git am 0001-Membuat-Modul-3.patch
Applying: Membuat Modul 3

Hasilnya? Akan ada sebuah commit baru dengan pesan ‘Membuat Modul 3’;  perubahannya persis seperti perubahan yang dilakukan oleh Bram (menambah file modul3.txt).

Edi ternyata tidak senang dengan perubahan yang dilakukan oleh Bram dan ingin membatalkan commit tersebut.   Ia memberikan perintah berikut ini:

$ git reset --hard master~1

Commit yang berdasarkan patch file dari Bram langsung hilang seketika.   Di saat Bram men-pull perubahan dari upstream, ia tidak akan menemukan perubahan yang dibuatnya.   Btw, Edi menyediakan server yang memakai git-daemon (melayani protokol git) dengan konfigurasi read only (default) sehingga Bram tetap dapat men-pull perubahan dari upstream kapan saja tanpa bisa men-push.

Beberapa rekan Edi dan Bram yang ingin bergabung dalam proyek merasa segan melihat banyak perintah Git yang harus dihafal.   Beruntungnya, IDE modern umumnya sudah mendukung Git sehingga pengguna tidak perlu lagi mengetik perintah Git.   Sesungguhnya bila sebuah IDE masih belum mendukung VCS seperti Git, maka ia tidak pantas menyandang predikat ‘IntegratedDevelopment Environment (IDE), yang seharusnya memiliki nilai tambah dibanding sebuah editor file!   Sebagai contoh, pada IntelliJ IDEA, terdapat menu VCS seperti yang terlihat pada gambar di bawah ini:

Git di IntelliJ IDEA

Git di IntelliJ IDEA

Tampilan diff (perbandingan riwayat file) di IDE umumnya lebih mudah dipahami dan lebih menarik, seperti yang terlihat pada gambar berikut ini:

Membandingkan file yang dulu dan sekarang

Membandingkan file yang dulu dan sekarang

Pada NetBeans, dukungan untuk Git terletak di menu Team, seperti yang terlihat pada gambar berikut ini:

Git di NetBeans

Git di NetBeans

Pada Eclipse, juga terdapat dukungan Git yang diperoleh dengan men-install plugin EGit, seperti yang terlihat pada gambar berikut ini:

Git di Eclipse

Git di Eclipse

Perihal Solid Snake
I'm nothing...

Apa komentar Anda?

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: