Rebase vs merge: yang bikin konflik bukan Git-nya, tapi kebiasaan tim
Pertanyaan: kalau dua orang kerja di branch sama, kapan rebase bikin hidup enak dan kapan bikin tim saling bunuh?
Dua model, satu perbedaan fundamental
merge bikin commit baru (Merge branch 'x' into 'y') yang menyatukan dua histori. Sejarahnya bercabang, jujur, tapi berantakan.
rebase menulis ulang commit kamu di atas base baru. Commit lama dibuang, dibuat versi baru dengan hash baru. Histori jadi garis lurus — tapi setiap commit itu adalah commit berbeda secara identitas.
Ini akar semua drama. Bukan soal selera estetika. Soal hash berubah.
Aturan besi yang tidak bisa ditawar
Jangan pernah rebase commit yang sudah di-push ke branch bersama.
Kalau kamu rebase main atau branch yang di-pull orang lain, kamu menciptakan dua versi histori dengan hash berbeda. Orang lain pull, Git melihat commit yang "hilang" lalu commit "baru" — hasilnya duplikat, konflik aneh, atau orang lain mem-push balik versi lama dan kerjaanmu lenyap dari branch. Ini bukan teori; ini penyebab nomor satu "kok kode gue ilang".
Branch milikmu sendiri yang belum di-review? Bebas rebase sepuasnya. Itu memang gunanya.
Pembagian kerja yang waras
| Situasi | Pakai | Alasan |
|---|---|---|
Update branch fitur dari main |
rebase |
Histori fitur tetap bersih, tidak ada merge commit sampah |
Gabung fitur ke main |
merge (idealnya --no-ff) |
Jejak fitur utuh, mudah revert satu fitur |
| Branch sudah di-push & di-review orang | merge |
Rebase = histori orang lain rusak |
| Rapikan commit sebelum buka PR | rebase -i |
Ini justru wajib; belum ada yang bergantung padanya |
| Hotfix kecil ke production | cherry-pick lalu merge |
Tidak mau bawa semua commit fitur |
Pola paling umum di tim sehat: rebase untuk sinkronisasi, merge untuk integrasi.
Contoh konkret: alur harian
# pagi, ambil update main tanpa bikin merge commit
git switch main && git pull --ff-only
git switch feat/checkout
git rebase main # commit-mu dipindah ke atas main terbaru
# konflik? selesaikan per commit, bukan sekaligus
git status # lihat file konflik
# edit file, lalu:
git add <file>
git rebase --continue
# nyerah di tengah jalan:
git rebase --abort # kembali persis seperti sebelum rebase
--abort itu jaring pengaman. Selama kamu ingat itu, rebase tidak menakutkan.
Tiga jebakan yang bikin tim rusak
1. Rebase branch yang sudah di-push, lalu push --force.
Kalau terpaksa (branch sendiri, sudah di-push karena buka PR), selalu pakai:
git push --force-with-lease
Bukan --force. --force-with-lease menolak push kalau remote sudah bergerak sejak kamu fetch terakhir. Artinya: kalau ada orang lain push ke branch itu, kamu tidak menimpanya secara buta. --force akan menimpa tanpa bertanya. Bedanya kecil di command, besar di akibat.
2. Menyelesaikan konflik rebase seperti konflik merge.
Di rebase, kamu menyelesaikan konflik per commit, berulang kali untuk konflik yang sama. Ini melelahkan dan gampang salah. Solusi: aktifkan rerere (reuse recorded resolution) — Git mengingat cara kamu menyelesaikan konflik dan menerapkannya otomatis di commit berikutnya.
git config --global rerere.enabled true
Sekali setup, seumur hidup hemat.
3. Histori linear dipuja berlebihan.
Tim yang mewajibkan "histori harus lurus 100%" biasanya berakhir dengan orang menghabiskan 40 menit rebase konflik untuk perubahan tiga baris. Merge commit itu bukan dosa. Yang dosa adalah merge commit dari git pull tanpa sadar, tercampur dengan commit kerjaan asli, di branch fitur yang berisi 30 commit "wip".
Sebelum buka PR: rapikan, jangan sembunyikan
rebase -i untuk menggabung commit berantakan jadi commit yang masuk akal:
git rebase -i main
# di editor: squash / fixup / reword / drop
Aturan praktis: satu commit = satu perubahan yang bisa dijelaskan dalam satu kalimat dan di-revert sendiri tanpa merusak yang lain. Kalau commit-mu berjudul "fix", "fix lagi", "benerin test", itu bukan commit — itu catatan harian.
Bonus yang jarang dipakai tapi emas saat review:
git range-diff main..old-version main..new-version
Bandingkan dua versi branch setelah rebase. Berguna banget waktu reviewer bilang "apa yang berubah sejak review terakhir?" dan kamu sudah rebase sehingga hash semua berubah.
✅ Satu hal yang bisa langsung dipakai
Set sekali, seumur repo:
git config --global pull.rebase true
git config --global rerere.enabled true
git config --global merge.conflictStyle zdiff3
pull.rebase true→git pulltidak lagi bikin merge commit tak sengaja.rerere.enabled true→ konflik yang sama tidak diselesaikan dua kali.zdiff3→ konflik menampilkan baris common ancestor juga, jadi kamu lihat niat asli kedua sisi, bukan cuma dua versi final yang bertabrakan. Konflik jadi jauh lebih mudah dipahami.
Dan ganti kebiasaan --force jadi --force-with-lease di muscle memory.
🧠 Takeaway
Rebase milikmu, merge milik bersama. Selama commit belum jadi konsumsi orang lain, rapikan sesukamu. Begitu orang lain bergantung padanya, sejarah itu bukan milikmu lagi.