Belajar Memakai Git Rebase

Fasilitas rebase di Git dapat dipakai untuk memodifikasi riwayat commit yang sudah ada. Sebagai contoh, rebase dapat dipakai untuk menggantikan merge. Walaupun memberikan hasil yang sama, keduanya memiliki ‘efek samping’ yang berbeda. Operasi merge akan menghasilkan commit baru sementara rebase tidak! Dengan demikian, rebase menghasilkan riwayat yang lebih rapi tanpa percabangan. Walaupun demikian, rebase sebaiknya tidak dipakai bila branch sudah dipublikasikan dan dipakai oleh orang lain. Operasi rebase biasanya hanya untuk merapikan branch yang masih di komputer lokal dan belum dipublikasikan ke server Git.

Untuk menunjukkan penggunaan rebase, anggap saja saya sedang mengerjakan sebuah proyek yang sudah mencapai versi 0.8 dimana isi branch master terlihat seperti pada gambar berikut ini:

Kondisi awal riwayat commit

Kondisi awal riwayat commit

Setelah merilis versi tersebut, saya kemudian membuat sebuah branch baru yang mewakili versi 0.9. Tidak lupa saya juga melakukan merge untuk branch lama ke master. Setelah itu, saya melakukan beberapa perubahan baru untuk versi terbaru (0.9) seperti yang terlihat pada gambar berikut ini:

Membuat branch baru dari master

Membuat branch baru dari master

Pada saat sedang mengembangkan fitur yang dijadwalkan untuk 0.9, saya memperoleh permintaan untuk menyelesaikan kesalahan yang ada di versi 0.8. Karena proritasnya sangat tinggi, saya harus menyelesaikan perubahan pada versi 0.8.1 dan menunda perubahan pada versi 0.9. Saya melakukan cukup banyak perubahan sehingga alur history saya terlihat seperti berikut ini:

Melakukan perubahan pada branch lama

Melakukan perubahan pada branch lama

Sekarang, setelah satu minggu berlalu, saya ingin lanjut mengerjakan apa yang tertunda di branch untuk versi 0.9. Tapi saya sudah melakukan banyak perubahan di versi 0.8 yang sudah di-merge ke branch master. Sementara itu, branch untuk versi 0.9 saat ini masih tetap berisi kode program lama sebelum perubahan versi 0.8.1 ke atas. Untuk memperbaharui branch versi 0.9 agar merujuk pada kode program terbaru di master, saya dapat menggunakan perintah seperti berikut ini:

$ git checkout develop_0.9
Switched to branch 'develop_0.9'

$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: Set versions to 0.9
Using index info to reconstruct a base tree...
M       application.properties
Falling back to patching base and 3-way merge...
Auto-merging application.properties
CONFLICT (content): Merge conflict in application.properties
Failed to merge in the changes.
Patch failed at 0001 Set versions to 0.9
The copy of the patch that failed is found in:
   c:/test/.git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

Pesan kesalahan di atas adalah jenis pesan kesalahan yang umum muncul bila terjadi konflik file yang tidak dapat diselesaikan secara otomatis. Yang perlu saya lakukan adalah mengubah file yang bermasalah dan melanjutkan proses rebase seperti yang terlihat pada perintah berikut ini:

$ vi application.properties

$ git add application.properties

$ git rebase --continue
Applying: Set versions to 0.9
Applying: Use c3p0 connection pool.

Sekarang, riwayat akan terlihat seperti pada gambar berikut ini:

Riwayat commit setelah rebase

Riwayat commit setelah rebase

Seluruh perubahan yang saya lakukan di master kini juga muncul di branch untuk versi 0.9. Riwayat terlihat kembali lurus sehingga terlihat rapi.

Sebagai perbandingan, selain memakai rebase, saya juga dapat memakai merge untuk mencapai hasil yang sama, misalnya dengan perintah seperti berikut ini:

$ git merge master
Auto-merging application.properties
CONFLICT (content): Merge conflict in application.properties
Automatic merge failed; fix conflicts and then commit the result.

$ vi application.properties

$ git commit -a -m 'Setelah perubahan 0.8.1'
[develop_0.9 e61a379] Setelah perubahan 0.8.1

Hasil dari merge adalah history seperti pada gambar berikut ini:

Riwayat commit setelah merge

Riwayat commit setelah merge

Terlihat bahwa bila saya memakai merge, commit yang sudah ada untuk branch 0.9 tidak berubah sama sekali. Yang ada adalah commit baru ditambahkan pada branch ini kemudian selisihnya (delta perubahan atau diff) diberikan sebagai sebuah commit baru. Terlihat bahwa penggunaan merge membuat history menjadi tidak rapi lagi, tapi tepat dipakai bila commit yang sudah ada tidak boleh diubah lagi (misalnya telah digunakan oleh developer lagi).

Fungsi lain dari rebase adalah merapikan riwayat commit yang ada, misalnya menghapus commit yang sudah dibuat. Karena Git menyimpan setiap commit sebagai delta dari commit sebelumnya dalam bentuk tree, maka tentu saja saya tidak bisa leluasa menghapus sebuah commit di posisi mana saja sesuka hati (karena setiap commit selalu berhubungan dengan commit sesudahnya). Sebagai contoh, saya memiliki riwayat seperti yang terlihat pada gambar berikut ini:

Kondisi awal riwayat history

Kondisi awal riwayat history

Bila saya ingin menggabungkan 9 commit terakhir menjadi sebuah commit tunggal, maka saya dapat memberikan perintah seperti berikut ini:

$ git rebase -i HEAD~10

Saya kemudian mengubah isi file yang muncul menjadi seperti yang terlihat pada gambar berikut ini:

reword f64b06f Set versions to 0.8.2
fixup 6b5e3cb Change invoice's layout.
fixup 368e0af Add sales report for every products.
fixup 494c91f Add vertical stretch when overflow for product's name.
fixup 0fd37c0 Allow filtering receivable report by invoice periods and region.
fixup 5036f32 Fixes product's quantity with zero value was displayed.
fixup eabcf75 Add warehouse name to report.
fixup 830e5f9 Minor changes to layout.
fixup b46d934 Add line separator.
fixup 68384e9 Sort report data.

Pada file tersebut, saya memilih reword untuk mengubah pesan commit dan fixup untuk menggabungkan sebuah commit dengan commit di atasnya. Selain kedua perintah tersebut, saya juga dapat memberikan perintah lain seperti pick untuk tidak melakukan perubahan, edit untuk mengubah perubahan yang dilakukan oleh commit tersebut, squash yang bekerja seperti fixup dimana saya bisa mengisi pesan commit baru, dan exec untuk mengerjakan perintah shell. Saya juga bisa menghapus sebuah commit dengan menghapus baris yang mewakili commit tersebut.

Setelah menyimpan file di atas, proses rebase akan dimulai. Karena saya mengisi reword pada commit terakhir, maka sebuah editor kembali muncul untuk menanyakan pesan commit terbaru. Saya pun mengisi nama pesan commit baru dan menyimpan file. Setelah proses rebase selesai, saya akan menemukan riwayat seperti yang terlihat seperti pada gambar berikut ini:

Kondisi riwayat commit setelah rebase interaktif yang memakai perintah reword dan fixup

Kondisi riwayat commit setelah rebase interaktif yang memakai perintah reword dan fixup

Seluruh perubahan yang saya lakukan sudah digabungkan menjadi sebuah commit tunggal.

Bagaimana bila saya membuat kesalahan pada saat melakukan rebase? Salah satu fasilitas dari Git adalah setiap kali terdapat perubahan posisi terakhir dari sebuah branch, posisi tersebut akan disimpan pada reflog. Secara default, perintah git gc hanya akan menghapus reflog yang sudah lebih dari 90 hari. Jadi, terdapat peluang sangat besar untuk memperbaiki kesalahan rebase yang baru saja dilakukan.

Untuk melihat informasi reflog, saya memberikan perintah seperti berikut ini:

$ git reflog

Setelah menentukan posisi branch yang benar (seperti HEAD@{1} dan sebagainya), saya kemudian memberikan perintah berikut ini untuk mengembalikan branch tersebut ke kondisi yang diharapkan:

$ git reset --hard HEAD@{1}

Perintah di atas akan mengembalikan posisi branch saat ini ke posisi yang telah ditentukan. Commit yang sudah dihapus dan digabungkan tetap akan dikembalikan seperti semula.

Belajar Memakai Stashing Di Git

Salah satu fitur menarik di Git adalah stashing.   Dengan melakukan stashing, developer dapat dengan mudah ‘melenyapkan‘ perubahan kode program, melakukan perubahan lain, lalu kembali lagi ke kode program yang sebelumnya dikerjakan.   Langkah-langkah tersebut sebenarnya dapat diwakili oleh beberapa perintah Git lainnya, tapi stashing membuatnya menjadi mudah karena hanya perlu memanggil satu perintah.

Sebagai contoh, saya akan menggunakan Git yang diakses melalui IntelliJ IDEA.   Saya membuat sebuah proyek Groovy baru dengan nama latihan.   Lalu saya membuat sebuah script Groovy sederhana bernama Latihan.groovy untuk menghitung sisa inventory secara FIFO, seperti berikut ini:

List  pembelian = [10, 20, 30, 40]
List penjualan = [5, 6, 3, 2, 1, 3]
println stokFifo(pembelian, hitungTotal(pembelian, penjualan))

int hitungTotal(List pembelian, List penjualan) {
    pembelian.sum() - penjualan.sum()
}

List stokFifo(List pembelian, int sisa) {
    List hasil = []
    pembelian.each { int jumlah ->
        if (sisa > 0) {
            int delta = (jumlah >= sisa)? jumlah: sisa  // BUG YANG DISENGAJA!
            sisa -= delta
            hasil << delta
        }
    }
    hasil
}

Untuk menambahkan proyek ke dalam repository Git, saya memlih menu VCS, Import into Version Control, Create Git Repository… seperti yang terlihat pada gambar berikut ini:

Membuat Repository Baru

Membuat Repository Baru

Pada kotak dialog yang muncul, saya memilih untuk meletakkan repository bersamaan dengan lokasi proyek dan kemudian men-klik tombol OK.

Kemudian, saya men-klik kanan pada file Latihan.groovy, memilih menu Git, Add seperti yang terlihat pada gambar berikut ini:

Menambahkan file ke index

Menambahkan file ke index

Sekarang file tersebut telah berada di lokasi index atau staging dari Git.   Berikutnya, saya akan men-commit perubahan.   Caranya adalah dengan memilih menu VCS, Commit Changes….  Akan muncul kotak dialog seperti yang terlihat pada gambar berikut ini:

Men-commit perubahan

Men-commit perubahan

Saya memilih tombol Commit untuk menyimpan perubahan dalam repository Git lokal.   Saat IntelliJ IDEA memunculkan dialog mengenai file lain yang tidak ikut di-commit, saya memilih No.

Anggap saja ini adalah sebuah aplikasi yang dikembangkan bersama dengan developer lain, yaitu Lena.   Gadis manis tersebut telah men-fetch repository saya dari remote/upstream, kemudian ia akan men-develop kode program yang berhubungan dengan kode program saya di atas.

Tentu saja saya juga tidak ingin ketinggalan sibuk.   Saya menambahkan harga dan perhitungan laba pada kode program saya.  Sambil mendengarkan lagu klasik, saya menulis kode program berikut ini:

Map pembelian = [10: 10000, 20: 10100, 30: 10200, 40: 11000]
Map penjualan = [5: 12000, 6: 13000, 3: 11000, 2: 11000, 1: 15000, 3: 12000]
println stokFifo(pembelian, hitungTotal(pembelian.keySet().toList(), penjualan.keySet().toList()))

int hitungTotal(List pembelian, List penjualan) {
    pembelian.sum() - penjualan.sum()
}

List stokFifo(Map pembelian, int sisa) {
    List hasil = []
    pembelian.each { jumlah, hargaBeli ->
        if (sisa > 0) {
            int delta = (jumlah >= sisa)? jumlah: sisa  // BUG YANG DISENGAJA!
            sisa -= delta
            hasil << [delta, hargaBeli]
        }
    }
    hasil
}

int hitungProfit(List stokFifo, Map penjualan) {
    def

Saya belum selesai mengetik, bahkan belum sempat menjalankan kode program ketika tiba-tiba telepon berdering.   Suara Lena terdengar sangat panik.   Dia mengatakan bahwa 30 menit lagi dirinya harus memberikan presentasi ke pengguna, tapi ada yang aneh dengan perhitungan inventory buatan saya!   Lena menemukan sebuah kesalahan.  Lebih dari itu, Lena meminta saya untuk segera memperbaikinya secepat mungkin sehingga dia bisa men-pull perbaikan dari saya!

Masalahnya: saya sudah mengubah banyak kode program tersebut sehingga tidak sama lagi seperti yang dipakai oleh Lena.   Saya tidak ingin menghapus perubahan yang sudah saya buat sejauh ini karena nantinya perubahan ini pasti akan dipakai.

Salah satu solusi yang dapat saya pakai adalah dengan memakai fasilitas stashing di Git.   Saya memilih menu VCS, Git, Stash Changes…. Pada kotak dialog yang muncul, saya mengisi seperti berikut ini:

Men-push stash baru

Men-push stash baru

Setelah men-klik tombol Create Stash, isi kode program saya secara ajaib kembali lagi seperti semula!  Sama persis seperti commit terakhir yang dirujuk oleh HEAD.   Saya segera memanfaatkan kesempatan ini untuk mencari dan memperbaiki kesalahan yang ditemukan Lena:

List  pembelian = [10, 20, 30, 40]
List penjualan = [5, 6, 3, 2, 1, 3]
println stokFifo(pembelian, hitungTotal(pembelian, penjualan))

int hitungTotal(List pembelian, List penjualan) {
    pembelian.sum() - penjualan.sum()
}

List stokFifo(List pembelian, int sisa) {
    List hasil = []
    pembelian.each { int jumlah ->
        if (sisa > 0) {
            int delta = (jumlah >= sisa)? sisa: jumlah
            sisa -= delta
            hasil << delta
        }
    }
    hasil
}

Saya segera men-commit perubahan dengan memilih menu VCS, Commit Changes….   Pada komentar, saya mengisi dengan ‘Perbaikan perhitungan sisa inventory yang salah.’ dan men-klik tombol Commit.   Saya kemudian men-push perubahan ke upstream, sehingga Lena bisa men-pull perubahan dari saya.   Tidak lama kemudian suara Lena terdengar lega seolah-olah baru saja luput dari malapetaka.  Ia memberitahukan bahwa kini semuanya baik-baik saja.

Lalu bagaimana dengan kode program yang sedang saya ‘ketik‘ sebelum menerima telepon dari Lena?  Kemana perginya?   Saya bisa mengembalikannya dengan memilih menu VCS, Git, UnStash Changes….   Pada kotak dialog yang muncul, saya men-klik tombol Pop Stash seperti yang terlihat pada gambar berikut ini:

Men-pop dari Stash

Men-pop stash

Kode program saya akan kembali seperti terakhir kali:

Map pembelian = [10: 10000, 20: 10100, 30: 10200, 40: 11000]
Map penjualan = [5: 12000, 6: 13000, 3: 11000, 2: 11000, 1: 15000, 3: 12000]
println stokFifo(pembelian, hitungTotal(pembelian.keySet().toList(), penjualan.keySet().toList()))

int hitungTotal(List pembelian, List penjualan) {
    pembelian.sum() - penjualan.sum()
}

List stokFifo(Map pembelian, int sisa) {
    List hasil = []
    pembelian.each { jumlah, hargaBeli ->
        if (sisa > 0) {
            int delta = (jumlah >= sisa)? sisa: jumlah
            sisa -= delta
            hasil << [delta, hargaBeli]
        }
    }
    hasil
}

int hitungProfit(List stokFifo, Map penjualan) {
    def

Tunggu dulu!  Tidak persis sama seperti terakhir kali!!  Fasilitas stashing bukan saja hanya mengembalikan kode program sebelumnya, tetapi juga melakukan merging dengan perubahan saat ini.   Perbaikan yang diminta oleh Lena tidak hilang setelah saya men-pop stash.

Pada contoh ini, hanya terdapat satu file yang berubah.   Fasilitas stashing akan semakin berguna bila perubahan telah dilakukan pada banyak file yang berbeda.  Tanpa Git dan stashing, pada kasus ini, saya harus memakai cara manual yang lebih repot seperti memberikan komentar atau mengedit file untuk sementara.

Belajar Menggunakan Branching Di Git

Ada kalanya pengembangan perangkat lunak tidak selalu berlangsung linear.   Pada kondisi tertentu, pengembangan bisa menjadi bercabang (disebut juga branching).   Sebagai contoh, anggap saja saya mengembangkan sebuah framework internal untuk keperluan pribadi.   Framework versi 1 (V1) sudah dipakai pada beberapa proyek saya. Lalu, mengambil pelajaran dari pengalaman, saya berniat melakukan perubahan drastis pada framework internal tersebut menjadi versi 2 (V2) yang TIDAK compatible dengan V1.  Proyek yang memakai framework V1 tidak bisa begitu saja men-upgrade ke framework V2.   Pengembangan framework versi 1 menjadi versi 2 bukankah terlihat sangat ‘lurus’ linear?  Bukankah begitu?

Proyek lama masih tetap memakai framework versi 1.   Saya tidak ingin menanggung resiko upgrade ke framework versi 2 karena proyek lama sudah dipakai.   Tapi permasalahannya:  saya tetap harus men-support proyek lama.   Bila ada keluhan yang berkaitan dengan bug di framework versi 1,  saya harus memperbaikinya dan merilis versi 1.1 dan seterusnya untuk dipakai oleh proyek lama.   Sementara itu, saya juga tetap harus mengembangkan develop dan memperbaiki framework versi 2 menjadi versi 2.1 dan seterusnya.   Beberapa perubahan yang saya lakukan pada versi 1 harus diterapkan pada versi 2 karena pada dasarnya kode program untuk versi 2 dilahirkan dari kode program versi 1.  Sekarang kondisinya tidak lagi linear, bukan?

Kasus di atas adalah salah satu alasan untuk melakukan percabangan (branching).   Beruntungnya, saya tidak perlu terlalu khawatir karena Git dapat menangani skenario di atas dengan baik.   Pada Git, sebuah branch adalah kumpulan hasil commit yang diberi pengenal tertentu (lebih tepatnya branch adalah referensi ke sebuah commit terakhir).   Setiap kali berpindah branch, maka struktur direktori dan isi file di working directory akan disesuaikan dengan kondisi untuk keadaan branch tersebut.   Git menyimpan struktur direktori dalam bentuk tree dan isi file dalam bentuk blob di dalamn folder bernama .git.   Berdasarkan informasi ini, Git dapat mengubah-ubah (atau memproduksi ulang) struktur direktori dan isi file secara mudah.  Ini merupakan salah satu fitur andalan Git yang membuatnya populer.

Sebagai contoh, saya akan membuat sebuah repository baru seperti berikut ini:

$ git init framework
Initialized empty Git repository in c:/Users/Snake/Desktop/framework/.git/

$ cd framework

$ git config 'user.name' 'Snake'

$ git config 'user.email' 'snake@dev.com'

Git secara default akan membuat sebuah branch dengan nama master.   Dengan demikian, saat ini repository saya sedang berada di branch master.  Saya dapat memulai branch V1 dengan memberikan perintah:

$ git checkout -b V1
Switched to a new branch 'V1'

Lalu saya mensimulasikan beberapa perubahan yang saya lakukan pada framework versi 1 seperti berikut ini:

$ mkdir core

$ echo 'Ini source core' >> core/core.txt

$ git add .
warning: LF will be replaced by CRLF in core/core.txt.
The file will have its original line endings in your working directory.

$ git commit -m 'Development untuk core'
[V1 (root-commit) ce68760] Development untuk core
warning: LF will be replaced by CRLF in core/core.txt.
The file will have its original line endings in your working directory.
 1 file changed, 1 insertion(+)
 create mode 100644 core/core.txt

$ mkdir shared

$ echo 'Ini shared code' >> shared/shared.txt

$ git add .
warning: LF will be replaced by CRLF in shared/shared.txt.
The file will have its original line endings in your working directory.

$ git commit -m 'Development untuk shared'
[V1 0e34b49] Development untuk shared
warning: LF will be replaced by CRLF in shared/shared.txt.
The file will have its original line endings in your working directory.
 1 file changed, 1 insertion(+)
 create mode 100644 shared/shared.txt

Sampai disini, struktur direktori saya adalah seperti berikut ini:

$ ls -R
.:
core  shared

./core:
core.txt

./shared:
shared.txt

Anggap saja struktur direktori ini mewakili framework versi 1 yang telah dirilis dan dipakai oleh proyek-proyek sebelummnya.

Lalu, dari sini saya berencana melakukan perubahan besar, yaitu dengan menghapus folder core dan membuat folder baru bernama core_baru.  Ini akan menjadi framework versi 2.   Saya akan mulai dengan membuat branch baru dengan perintah berikut ini:

$ git checkout -b V2
Switched to a new branch 'V2'

Saya mensimulasikan beberapa perubahan pada versi 2, yaitu:

$ rm -Rf core

$ mkdir core_baru

$ echo 'Ini adalah core baru' >> core_baru/core.txt

$ git add --all
warning: LF will be replaced by CRLF in core_baru/core.txt.
The file will have its original line endings in your working directory.

$ git commit -m 'Development untuk core baru'
[V2 warning: LF will be replaced by CRLF in core_baru/core.txt.
The file will have its original line endings in your working directory.
e6e7d19] Development untuk core baru
warning: LF will be replaced by CRLF in core_baru/core.txt.
The file will have its original line endings in your working directory.
 2 files changed, 1 insertion(+), 1 deletion(-)
 delete mode 100644 core/core.txt
 create mode 100644 core_baru/core.txt

Sampai disini, bila saya melihat informasi branch untuk repository, saya akan menemukan hasil seperti berikut ini:

$ git branch -a
  V1
* V2

$ ls -R
.:
core_baru  shared

./core_baru:
core.txt

./shared:
shared.txt

Framework versi 2 sekarang sudah selesai dibuat.

Suatu hari, saya mendapatkan laporan dari developer yang menemukan adanya bug kritis di shared.txt.   Bug ini harus segera diperbaiki dan seluruh proyek lama harus segera di-update agar memakai framework yang telah diperbaiki.   Karena proyek lama terikat pada framework versi 1, maka saya melakukan perubahan pada branch V1.   Untuk itu, saya segera beralih ke branch V1 dengan perintah berikut ini:

$ git checkout V1
Switched to branch 'V1'

$ ls -R
.:
core  shared

./core:
core.txt

./shared:
shared.txt

Saat saya beralih ke branch V1, struktur pada working directory kembali ke kondisi lama dimana terdapat folder core.   Sementara itu, folder core_baru yang ada di V2 tidak terlihat disini.   Saya segera melakukan perbaikan bug yang disimulasikan dengan:

$ echo 'Ada perbaikan bug penting!' >> shared/shared.txt

$ cat shared/shared.txt
Ini shared code
Ada perbaikan bug penting!

$ git commit -a -m 'Perbaikan bug penting!'
warning: LF will be replaced by CRLF in shared/shared.txt.
The file will have its original line endings in your working directory.
[V1 warning: LF will be replaced by CRLF in shared/shared.txt.
The file will have its original line endings in your working directory.
213674f] Perbaikan bug penting!
warning: LF will be replaced by CRLF in shared/shared.txt.
The file will have its original line endings in your working directory.
 1 file changed, 1 insertion(+)

Anggap saja bug terdapat pada file shared.txt.  Saya telah men-commit perubahan file shared.txt yang telah diperbaiki.

Sebagai bonus, saya juga melakukan penambahan fitur.  Perubahan ini khusus untuk framework versi 1 saja dan tidak berlaku untuk versi 2.  Sebagai simulasi, saya memberikan perintah:

$ echo 'Ini fitur baru untuk versi lama' >> core/fitur.txt

$ git add core/fitur.txt
warning: LF will be replaced by CRLF in core/fitur.txt.
The file will have its original line endings in your working directory.

$ git commit -a -m 'Penambahan fitur baru'
[V1 62c536a] Penambahan fitur baru
warning: LF will be replaced by CRLF in core/fitur.txt.
The file will have its original line endings in your working directory.
 1 file changed, 1 insertion(+)
 create mode 100644 core/fitur.txt

Tugas saya telah selesai.   Proyek yang memakai versi 1 dapat segera di-update untuk memakai perubahan terbaru tersebut.

Tapi ada satu masalah baru yang muncul:  saat saya kembali ke branch V2, perubahan di shared.txt tidak akan diikutsertakan.   Hal ini karena perubahan sebelumnya saya lakukan di branch V1.  Tapi bila perubahan tidak diterapkan di V2, maka bug yang diperbaiki di V1 akan muncul kembali di V2.   Untuk memeriksanya, saya menggunakan perintah berikut ini:

$ git checkout V2
Switched to branch 'V2'

$ ls -R
.:
core_baru  shared

./core_baru:
core.txt

./shared:
shared.txt

$ cat shared/shared.txt
Ini shared code

Bila branch V2 masih belum di-push ke upstream (belum di-‘lihat‘ orang lain), maka saya dapat melakukan rebase, seperti yang ditunjukkan pada perintah berikut ini:

$ git rebase V1~
First, rewinding head to replay your work on top of it...
Applying: Development untuk core baru

$ ls -R
.:
core_baru  shared

./core_baru:
core.txt

./shared:
shared.txt

$ cat shared/shared.txt
Ini shared code
Ada perbaikan bug penting!

Saya memakai V1~ untuk merujuk pada commit sebelum commit terakhir di branch V1.   Hal ini karena commit terakhir: ‘Penambahan fitur baru‘, tidak perlu disertakan pada branch V2.   Nilai V1~ sama seperti merujuk pada commit dengan keterangan ‘Perbaikan bug penting!‘.   Selain memakai notasi relatif tersebut, saya dapat langsung merujuk ke id commit secara langsung, dengan perintah seperti:

$ git rebase 213674f4a0528e16d26d32476fff303008be3ede
First, rewinding head to replay your work on top of it...
Applying: Development untuk core baru

Salah satu alasan untuk tidak menggunakan rebase adalah proses ini menyebabkan seluruh commit yang ada di branch V2 berubah.   Rebase menghasilkan commit baru dengan id yang baru.   Hal ini tidak masalah bila hanya saya satu-satunya yang melihat seluruh commit yang ada di branch V2.   Akan tetapi lain ceritanya bila terdapat developer lain yang pernah men-fetch (atau men-pull) branch V2 sebelumnya.   Seluruh commit yang mereka lihat di repository lokal mereka kini tidak lagi valid.   Hal ini bisa jadi membingungkan ketika mereka akan men-push ke upstream!

Solusi lainnya adalah dengan menggunakan merge.   Sebagai contoh, saya dapat mengganti perintah rebase di atas dengan perintah berikut ini:

$ git merge V1~
Merge made by the 'recursive' strategy.
 shared/shared.txt | 1 +
 1 file changed, 1 insertion(+)

$ ls -R
.:
core_baru  shared

./core_baru:
core.txt

./shared:
shared.txt

$ cat shared/shared.txt
Ini shared code
Ada perbaikan bug penting!

Perintah merge tidak akan mengubah commit yang sudah ada, tetapi akan menghasilkan sebuah merge commit.  Dengan memberikan perintah gitk, saya dapat melihat visualisasi hubungan setiap commit untuk branch V2, seperti yang terlihat pada gambar berikut ini:

Visualisasi isi branch dengan gitk

Visualisasi isi branch dengan gitk

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

Mengubah “Kode Program” Aptana Studio 3

Selama ini di lingkungan saya, seorang dosen dipandang terdiri atas 2 golongan: dosen praktisi yang mengisi waktu luang mengajar dimana mereka menceritakan pengalaman mereka, atau mereka yang serius mencari nafkah  dari “teori” pelajaran.   Cara berpikir seperti ini berujung pada pandangan bahwa dosen yang tidak terjun langsung bekerja di industri software memiliki prestige yang lebih rendah.  Saya sendiri memiliki pandangan berbeda dimana dunia akademis/penelitian dan dunia industri adalah dua hal yang berbeda tetapi saling melengkapi.  Pada dunia industri, para pekerja bekerja keras membangun sistem memenuhi kebutuhan bisnis.  Semantara saya memandang dunia akademis sebagai tempat dimana para peneliti mengamati teknik yang dipakai oleh beragam industri, mengembangkannya dan memperbaharuinya.  Sebagai contoh, seorang developer di industri hanya akan berkonsentrasi pada kode program Java dimana ia bisa menyelesaikan kerjaannya secara cepat.  Begitu juga developer PHP dan pekerjaannya.  Mereka umumnya tidak punya banyak waktu untuk bereksperimen dengan hal-hal diluar kebutuhan perusahaan.  Sementara itu, dosen/professor/peneliti punya banyak waktu untuk mengamati setiap bahasa, membandingkannya, menambahkan kemampuan atau menciptakan bahasa baru yang lebih efektif.  Dengan demikian, dalam pandangan saya, masing-masing memiliki peran penting yang tidak dapat digantikan, baik itu peneliti maupun praktisi.

Dikti sering kali me-“maksa” dosen untuk meneliti.  Ini adalah hal bagus.  Di bidang computer science (TI), para dosen bisa mulai dengan membongkar kode program open source.  Alangkah indahnya bila dosen yang mengajar matakuliah database adalah dosen yang sudah biasa mengotak-atik kode program MySQL yang bebas di-download. Hal ini sama halnya seperti  para calon dokter di-didik untuk memahami cara kerja organ tubuh secara detail dan rinci;  mereka tidak mungkin hanya perlu diajarin resep praktis seperti “kalau demam, kasih saja paracetamol dan vitamin”.  Selain itu, program open source dapat dipakai untuk menunjukkan kepada mahasiswa se-‘rumit’ apa sebuah software yang sehari-hari mereka pakai (yang menjadi alasan kenapa mereka butuh arsitektur yang jelas dan tidak membuat kode program sesuka hati sesuai mood).

Aptana Studio 3 adalah salah satu software open source berbasis Eclipse yang menarik untuk dijadikan bahan pembelajaran (atau penelitian).  Mengapa?  Karena saat mencoba memakai versi terbarunya, saya menemukan bahwa code assistant untuk jQuery tidak bekerja dengan baik.   Aptana Studio 3 dikembangkan dengan Eclipse RCP, sehingga kode program GUI-nya sudah adalah kode program Eclipse RCP.  Hal ini akan mempermudah memahami dan mengembangkan Aptana Studio 3.  Dosen pembimbing dan tim asistan lab, misalnya, dapat menambahkan fitur yang sering diperlukan oleh programmer  jQuery, seperti dukungan code assistant saat mengetik selector di jQuery;  mengetik $(“.b –> akan muncul code assistant untuk .baru dan .buat sesuai dengan class yang ada di HTML.

Sebelum mulai mengembangkan Aptana Studio 3, pertanyaan yang harus dijawab adalah bagaimana cara mengambil source code dan menghasilkan program dari source code tersebut? Langkah pertama adalah men-download  Eclipse for RCP and RAP Developers.  Ini adalah IDE yang dipakai untuk mengembangkan plugin  Eclipse dan aplikasi berbasis Eclipse RCP .  Versi yang disarankan adalah  http://www.eclipse.org/downloads/packages/eclipse-rcp-and-rap-developers/indigosr1.

Langkah berikutnya adalah mengambil source code dari Git.  Karena Eclipse for RCP and RAP Developers telah dilengkapi dengan plugin EGit, saya dapat langsung men-download dari dalam Eclipse.  Caranya adalah dengan memilih menu File, Import.  Kemudian saya memilih Git, Projects from Git dan men-klik tombol Next.  Lalu, saya men-klik tombol Clone… Pada dialog yang muncul, saya mengisi URI dengan git://github.com/aptana/studio3 seperti yang terlihat pada gambar berikut ini:

Memilih Source Git Repository

Memilih Source Git Repository

Lalu saya men-klik tombol Next.  Pada daftar Brach Selection, saya memilih Development untuk mendapatkan source code terbaru yang sedang dikerjakan oleh developer lain.  Setelah itu saya men-klik tombol Finish. Setelah kembali ke halaman Select A Git Repository, saya memilih repository studio3 dan men-klik tombol Next.  Lalu pada halaman berikutnya, saya memilih Import existing projects dan men-klik tombol Next.   Pada halaman berikutnya, saya memberi centang pada seluruh project yang ada dengan memilih Select All, kemudian saya men-klik tombol Finish. Saya memastikan sedang terkoneksi ke internet karena eGit akan men-download source code Aptana Studio 3 dari repository Git.

Setelah selesai, saya mengulangi hal yang sama untuk mengambil proyek yang ada di lokasi berikut ini:

  • git://github.com/aptana/studio3-rcp
  • git://github.com/aptana/libraries_com

Karena saya tidak akan bekerja dengan PHP, Python dan Ruby, saya tidak mengambil kode program yang tidak dibutuhkan.

Langkah berikutnya adalah menghilangkan pesan kesalahan pada kode program.  Aptana Studio 3 tidak menyertakan library FTP dengan alasan lisensi.  Beruntungnya, saya juga tidak butuh fitur FTP, sehingga saya bisa menghapus proyek plugin yang berhubungan dengan FTP. Karena telah menghapus plugin FTP, saya perlu menyesuaikan dengan dependency yang ada.   Beberapa perubahan yang saya lakukan adalah:

  1. Mengedit file MANIFEST.MF di com.aptana.ide.libraries.subcription dimana saya menghilangkan seluruh baris Export-Package yang ada.
  2. Membuka plugin com.aptana.syncing.ui.  Menghapus referensi ke com.aptana.filesystem.ftp.FTPConnectionPoint dan com.aptana.ui.ftp.internal.FTPPropertyDialogProvider di file SiteConnectionPropertiesWidget.java.  Juga menghapus referensi ke com.aptana.ui.ftp.preferences.UpdatePermissionsComposite di file SmartSyncDialog.java.
  3. Membuka MANIFEST.MF untuk com.aptana.syncing.ui.  Lalu menghapus baris yang mengandung com.aptana.filesystem.ftp dan com.aptana.ui.ftp.

Perubahan lain yang saya lakukan adalah:

  1. Plugin com.aptana.portal.ui.  Mengubah file BrowserFunctionWrapper.java dan BrowserWrapper.java dengan menghilangkan referensi ke com.aptana.swt.webkitbrowser.BrowserFunction.
  2. Menutup atau menghapus project yang diakhiri oleh tests karena project tersebut hanya dibutuhkan untuk pengujian.

Bagaimana cara mencari sebuah file secara cepat di tumpukan proyek yang segitu banyaknya?   Berikut ini adalah contoh tampilan project Eclipse yang ada:

Daftar Eclipse Project Yang Membentuk Aptana Studio 3

Daftar Eclipse Project Yang Membentuk Aptana Studio 3

Rasanya akan cape sekali mencari sebuah file dengan membuka setiap tree proyek satu per satu.  Saya selalu membiasakan diri menekan shortcut Ctrl+Shift+R di Eclipse.   Shortcut ini akan memunculkan dialog Open Resource dimana saya bisa melakukan pencarian dengan mengetikkan nama file seperti yang terlihat pada gambar berikut ini:

Dialog Open Resource

Dialog Open Resource

Untuk menjalankan program Aptana Studio 3, saya perlu membuka file aptana.product, kemudian memilih Launch an Eclipse application, seperti yang terlihat pada gambar berikut ini:

Menjalankan aplikasi

Menjalankan aplikasi

Bila seandainya perubahan telah selesai dibuat, saya harus membuat binary untuk distribusi.  Caranya adalah dengan membuka file aptana.product dan memilih Eclipse Product export wizard seperti yang terlihat pada gambar berikut ini:

Membuat binary distribusi untuk proyek

Membuat binary distribusi untuk proyek

Pada dialog Export, saya mengisi Directory dengan lokasi yang akan berisi binary distribusi.  Selain itu, saya juga menghilangkan tanda centang di Generate metadata repository.  Dialog Export akan terlihat seperti pada gambar berikut ini:

Dialog Export

Dialog Export

Setelah proses export selesai, saya bisa menjalankan Aptana Studio 3 hasil perubahan saya dengan membuka folder C:\Program Files\aptana\eclipse, lalu men-double click file AptanaStudio3.exe.