Fast-forward menuntut satu kemewahan yang jarang bertahan lama: main harus diam selagi fitur dikerjakan. Pada proyek hidup, main terus menerima commit — bug diperbaiki, fitur orang lain masuk — sehingga saat fitur kita siap digabungkan, kedua riwayat sudah menyimpang dari titik percabangan. Untuk situasi itu Git memakai three-way merge: ia menatap tiga versi sekaligus — titik percabangan, ujung main, ujung fitur — lalu membuat satu commit penggabung yang berbeda dari semua commit sebelumnya: commit berparent dua. Chapter ini menjalankan skenario itu dari nol dan membedah commit hasil merge sampai ke isi mentahnya.
Skenario: Kedua Sisi Sama-sama Maju #
Repository latihan sengaja dibuat saling menyimpang. Basisnya dua commit di main; fitur menambah berkas grafik.md di sisinya, sementara main menambah bagian kesimpulan di laporan.md:
mkdir latihan-merge && cd latihan-merge
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf '# Laporan\npendahuluan\n' > laporan.md
git add laporan.md
git commit -m "Tulis pendahuluan laporan"
printf '# Laporan\npendahuluan\ndata\n' > laporan.md
git add laporan.md
git commit -m "Tambah bagian data"
git switch -c fitur-grafik
printf '# Grafik\ngrafik-penjualan.png\n' > grafik.md
git add grafik.md
git commit -m "Tambah catatan grafik"
git switch main
printf '# Laporan\npendahuluan\ndata\nkesimpulan\n' > laporan.md
git add laporan.md
git commit -m "Tambah kesimpulan"Output yang Dihasilkan (perintah git switch main):
Switched to branch 'main'Titik percabangannya adalah commit “Tambah bagian data”. Sejak titik itu, fitur-grafik punya satu commit (grafik.md) dan main punya satu commit (laporan.md) — bukan garis lurus, jadi fast-forward mustahil: menarik main ke depan akan meninggalkan commit kesimpulan, bukan menggabungkan.
Merge Membuat Commit Baru #
Dari main, penggabungan dijalankan dengan pesan yang kita tentukan sendiri:
git merge fitur-grafik -m "Gabungkan fitur grafik"Output yang Dihasilkan:
Merge made by the 'ort' strategy.
grafik.md | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 grafik.mdBandingkan dengan keluaran fast-forward di chapter Fast-Forward Merge
: tidak ada baris Updating lama..baru, tidak ada kata Fast-forward. Sebagai gantinya muncul pernyataan Merge made by the 'ort' strategy. — Git membuat commit baru yang menggabungkan isi kedua sisi, dengan ort sebagai nama mesin penggabung internal (penerus strategi recursive yang lama). Diffstat di bawahnya merangkum hasil pembacaan tiga arah: berkas grafik.md hadir sebagai berkas baru, sementara suntingan laporan.md dari sisi main tetap utuh — kedua perubahan hidup berdampingan dalam satu snapshot.
Bedah Commit Merge: Dua Parent #
Komit penggabung bisa kita bongkar isi mentahnya dengan cat-file -p, persis seperti chapter Anatomi Commit
:
git cat-file -p HEADOutput yang Dihasilkan:
tree 12bd9e95d09ba41b068d6f147654fbad9a6f600c
parent 41610f13e05dafdbea0c37f0612a7be04bb079f2
parent a489db175c8af9649a65db9b124493b8c3f91aa0
author Budi Santoso <[email protected]> 1792032000 +0700
committer Budi Santoso <[email protected]> 1792032000 +0700
Gabungkan fitur grafikPerhatikan bagian parent — ada dua baris, dan itulah tanda tangan commit merge. Parent pertama adalah ujung main saat merge dijalankan; parent kedua ujung branch yang digabungkan. Kedua induknya bisa diperiksa satu per satu:
git cat-file -p HEAD^1Output yang Dihasilkan:
tree cabc75da152b687b8f9c6687a6d215a8768600f0
parent 93bc372bd3bfe866066a8f48600aa790a6e51b4c
author Budi Santoso <[email protected]> 1792031400 +0700
committer Budi Santoso <[email protected]> 1792031400 +0700
Tambah kesimpulangit cat-file -p HEAD^2Output yang Dihasilkan:
tree 884032cc9506d514fcc5e12bc4ca880533594eb2
parent 93bc372bd3bfe866066a8f48600aa790a6e51b4c
author Budi Santoso <[email protected]> 1792030800 +0700
committer Budi Santoso <[email protected]> 1792030800 +0700
Tambah catatan grafikKedua commit parent sama-sama hanya punya satu parent — yakni 93bc372, commit “Tambah bagian data” yang menjadi titik percabangan. Pemeriksaan singkat lewat rev-parse memastikan pasangan parent tersebut:
git rev-parse HEAD^1 HEAD^2Output yang Dihasilkan:
41610f13e05dafdbea0c37f0612a7be04bb079f2
a489db175c8af9649a65db9b124493b8c3f91aa0Notasi HEAD^1 dan HEAD^2 — induk pertama dan kedua — menjadi pintu menjelajah tiap sisi penggabungan, misalnya git log --oneline HEAD^2 untuk menelusuri hanya jalur fitur. Konvensi urutannya layak diingat: parent pertama selalu sisi tempat kita berdiri saat merge (main), parent kedua sisi yang dibawa masuk. Konvensi first-parent ini kelak dipakai opsi seperti git log --first-parent untuk membaca riwayat seolah percabangan tak pernah terjadi — satu alat baca yang berguna saat menelusuri rilis.
Riwayat yang Kini Berbentuk Graf #
Setelah penggabungan, git log tidak lagi bisa menggambar garis lurus:
git log --oneline --graphOutput yang Dihasilkan:
* 4ebf64f Gabungkan fitur grafik
|\
| * a489db1 Tambah catatan grafik
* | 41610f1 Tambah kesimpulan
|/
* 93bc372 Tambah bagian data
* d974a79 Tulis pendahuluan laporanCara membaca graf ini: baris teratas dengan * dan lekukan |\ adalah commit merge; cabang kiri (garis |) menaiki jalur main — “Tambah kesimpulan” — cabang kanan menaiki jalur fitur — “Tambah catatan grafik” — lalu keduanya bertemu di 93bc372 sebelum menyatu ke “Tulis pendahuluan laporan”. Dengan --decorate --all, label penunjuk ikut tertera:
git log --oneline --decorate --graph --allOutput yang Dihasilkan:
* 4ebf64f (HEAD -> main) Gabungkan fitur grafik
|\
| * a489db1 (fitur-grafik) Tambah catatan grafik
* | 41610f1 Tambah kesimpulan
|/
* 93bc372 Tambah bagian data
* d974a79 Tulis pendahuluan laporanBentuk akhirnya — persis cermin keluaran di atas:
Diagram dibaca dari kiri ke kanan: dua jalur berangkat dari 93bc372, berjalan sendiri-sendiri, lalu berhimpun kembali di commit merge 4ebf64f — simpul berparent dua itulah yang menjadikan riwayat sebuah graf, bukan lagi senarai. Hash pada diagram dan keluaran di atas milik mesin uji.
Konflik Itu Mungkin #
Skenario latihan ini sengaja memilih berkas yang berbeda di tiap sisi, sehingga penggabungan berjalan mulus. Ketika kedua sisi menyunting baris yang sama pada berkas yang sama, Git tidak berani memutuskan versi mana yang benar — ia menghentikan merge dan menyerahkan keputusan kepada kita. Kejadian itu bernama merge conflict: penampakan berkas ber-marka <<<<<<<, =======, >>>>>>>, dan langkah tenang menyelesaikannya — dibahas tuntas di chapter Merge Conflicts
dan Menyelesaikan Merge Conflicts
.
Tiga babak merge kini lengkap terbaca: penunjuk yang ditarik (fast-forward), commit penggabung berparent dua (three-way), dan janji konflik yang menyusul. Perintah git merge sendiri masih menyimpan beberapa kendali penting — memaksa commit penggabung pada garis lurus dengan --no-ff, atau menekan riwayat menjadi satu commit dengan --squash — dan kendali-kendali itu pokok chapter berikutnya: git merge
.