Dua babak penggabungan sudah kita jalankan — Fast-Forward Merge menarik penunjuk, Three-Way Merge membuat commit berparent dua — dan keduanya memakai satu perintah yang sama: git merge. Babak-babak itu sebenarnya cuma dua dari sekian banyak wajah perintah ini. Chapter ini membuka git merge selengkapnya: arah penggabungan yang selalu menuju branch aktif (kesalahan arah = hasil kebalik), opsi --no-ff dan --ff-only yang memperjuangkan bentuk riwayat, --squash yang meluruhkan seluruh fitur menjadi satu commit, serta --abort dan -m untuk situasi darurat. Rujukan resmi lengkapnya ada di git-scm.com/docs/git-merge .

Arah Penggabungan: Selalu ke Branch Aktif #

Aturan paling penting dari git merge <branch>: pekerjaan dari <branch> dibawa masuk ke branch tempat kita berdiri saat ini. “Berdiri di main, merge fitur” berarti fitur masuk ke main — bukan sebaliknya. Kita buktikan dengan repository yang kedua sisinya sama-sama maju:

bash
mkdir latihan-arah && cd latihan-arah
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf '# Situs\nberanda\n' > situs.md
git add situs.md
git commit -m "Buat halaman beranda"
printf '# Situs\nberanda\ntentang\n' > situs.md
git add situs.md
git commit -m "Tambah halaman tentang"
git switch -c fitur-kontak
printf '[email protected]\n' > kontak.md
git add kontak.md
git commit -m "Tambah alamat kontak"
git switch main
printf '# Situs\nberanda\ntentang\nfaq\n' > situs.md
git add situs.md
git commit -m "Tambah halaman faq"
git branch -v

Output yang Dihasilkan (perintah git branch -v):

text
  fitur-kontak 0324ae9 Tambah alamat kontak
* main         50420b4 Tambah halaman faq

Kedua riwayat sudah menyimpang: main berhenti di “Tambah halaman faq”, fitur-kontak berhenti di “Tambah alamat kontak”. Dari main kita gabungkan:

bash
git merge fitur-kontak -m "Gabungkan fitur kontak"

Output yang Dihasilkan:

text
Merge made by the 'ort' strategy.
 kontak.md | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 kontak.md

Diffstat menyebut kontak.md — berkas milik sisi fitur — karena itulah arah alirannya: masuk ke main. Posisi kedua penunjuk setelahnya:

bash
git branch -v

Output yang Dihasilkan:

text
  fitur-kontak 0324ae9 Tambah alamat kontak
* main         5dba16e Gabungkan fitur kontak

main maju ke commit penggabung baru; fitur-kontak tidak bergerak sedikit pun dari 0324ae9. Grafnya:

bash
git log --oneline --graph --all

Output yang Dihasilkan:

text
*   5dba16e Gabungkan fitur kontak
|\  
| * 0324ae9 Tambah alamat kontak
* | 50420b4 Tambah halaman faq
|/  
* a7106b5 Tambah halaman tentang
* 6f13e68 Buat halaman beranda

Ketika Arah Terbalik #

Perintah yang sama dijalankan dari sisi seberang akan menghasilkan kebalikan total. Kita bangun ulang repository yang identik, lalu berdiri di fitur-kontak dan menggabungkan main — tanpa -m, sehingga editor terbuka dengan pesan default; simpan dan tutup saja:

bash
git switch fitur-kontak
git merge main

Output yang Dihasilkan:

text
Merge made by the 'ort' strategy.
 situs.md | 1 +
 1 file changed, 1 insertion(+)
bash
git branch -v

Output yang Dihasilkan:

text
* fitur-kontak 4342899 Merge branch 'main' into fitur-kontak
  main         9fb3deb Tambah halaman faq
bash
git log --oneline --graph --all

Output yang Dihasilkan:

text
*   4342899 Merge branch 'main' into fitur-kontak
|\  
| * 9fb3deb Tambah halaman faq
* | e60db21 Tambah alamat kontak
|/  
* 1bc6f5c Tambah halaman tentang
* 6339829 Buat halaman beranda

Baca ketiganya dengan teliti: kini main yang diam di “Tambah halaman faq”, dan commit merge berparent dua justru lahir di ujung fitur-kontak. Diffstat pun terbalik — situs.md, berkas milik main, yang dibawa masuk. main tidak pernah menerima apa pun; penggabungan yang kita niatkan untuk “menyatukan fitur ke main” tidak terjadi.

Memaksa Commit Penggabung dengan –no-ff #

Skenario kedua: main diam total selagi fitur dikerjakan — kondisi fast-forward dari chapter Fast-Forward Merge . Merge biasa hanya akan menarik penunjuk tanpa jejak percabangan. --no-ff (no fast-forward) memaksa Git membuat commit penggabung walau fast-forward bisa dilakukan:

bash
mkdir latihan-no-ff && cd latihan-no-ff
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf 'a.md\n' > a.md
git add a.md
git commit -m "Commit dasar"
printf 'a.md\nb.md\n' > a.md
git add a.md
git commit -m "Tambah baris b"
git switch -c fitur-keranjang
printf 'kopi\ngula\n' > keranjang.md
git add keranjang.md
git commit -m "Susun keranjang belanja"
git switch main
git merge --no-ff fitur-keranjang

Output yang Dihasilkan (perintah git merge --no-ff fitur-keranjang):

text
Merge made by the 'ort' strategy.
 keranjang.md | 2 ++
 1 file changed, 2 insertions(+)
 create mode 100644 keranjang.md

Tiga baris keluaran itu sama persis dengan three-way merge: pernyataan Merge made by the 'ort' strategy. lalu diffstat. Bedanya cuma pemicu — di sini tidak ada penyimpangan riwayat sama sekali; commit penggabung muncul semata karena --no-ff memintanya. Editor pesan commit terbuka berisi default Merge branch 'fitur-keranjang'; kita terima apa adanya. Bentuk riwayat dan posisi hashnya:

bash
git log --oneline --graph --all
git rev-parse main fitur-keranjang

Output yang Dihasilkan (perintah git log --oneline --graph --all):

text
*   87893ab Merge branch 'fitur-keranjang'
|\  
| * 2da05f3 Susun keranjang belanja
|/  
* 23e8d5e Tambah baris b
* e219d35 Commit dasar

Output yang Dihasilkan (perintah git rev-parse main fitur-keranjang):

text
87893ab36b77b072d3692088478b4d5b8aaa077e
2da05f36186422ba334eddd6973f784cb54dc61a

Hash pada keluaran di mesin pembaca akan berbeda; yang penting polanya: main kini menunjuk commit merge 87893ab — hash baru yang tidak pernah ada di fitur-keranjang — sementara fitur-keranjang tetap di 2da05f3. Graf punya gelembung percabangan yang jujur: siapa pun yang membaca riwayat tahu bahwa keranjang pernah dikerjakan terpisah lalu digabungkan, informasi yang lenyap pada fast-forward polos. Kebalikannya, --ff-only menolak merge bila fast-forward tidak mungkin — keluaran fatalnya sudah kita saksikan di chapter Fast-Forward Merge .

Meluruhkan Riwayat dengan –squash #

--squash mengambil isi branch tanpa membuat commit merge: seluruh hasil penggabungan dijatuhkan ke staging area, menunggu satu commit dari kita. Skenarionya kedua sisi menyimpang seperti sebelumnya:

bash
mkdir latihan-squash && cd latihan-squash
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf '# Toko\nberanda\n' > situs.md
git add situs.md
git commit -m "Buat beranda toko"
git switch -c fitur-keranjang
printf 'kopi\n' > keranjang.md
git add keranjang.md
git commit -m "Tambah keranjang kosong"
printf 'kopi\ngula\n' > keranjang.md
git add keranjang.md
git commit -m "Isi keranjang"
git switch main
printf '# Toko\nberanda\ntentang\n' > situs.md
git add situs.md
git commit -m "Tambah halaman tentang"
git merge --squash fitur-keranjang

Output yang Dihasilkan (perintah git merge --squash fitur-keranjang):

text
Squash commit -- not updating HEAD
Automatic merge went well; stopped before committing as requested

Baris Squash commit -- not updating HEAD menegaskan inti opsi ini: HEAD dan branch aktif tidak digeser. Baris kedua mengabarkan penggabungan berjalan mulus dan Git sengaja berhenti sebelum membuat commit — persis seperti merge dengan --no-commit. Statusnya menunjukkan hasil sudah siap di staging area:

bash
git status

Output yang Dihasilkan:

text
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	new file:   keranjang.md

Kedua commit fitur — “Tambah keranjang kosong” dan “Isi keranjang” — kini meringkuk menjadi satu perubahan staged keranjang.md. Kita rangkai jadi satu commit biasa berparent satu:

bash
git commit -m "Gabungkan fitur keranjang dalam satu commit"

Output yang Dihasilkan:

text
[main 5736882] Gabungkan fitur keranjang dalam satu commit
 1 file changed, 2 insertions(+)
 create mode 100644 keranjang.md
bash
git log --oneline --graph --all
git branch -v

Output yang Dihasilkan (perintah git log --oneline --graph --all):

text
* 5736882 Gabungkan fitur keranjang dalam satu commit
* dd4c583 Tambah halaman tentang
| * 685a343 Isi keranjang
| * e334a69 Tambah keranjang kosong
|/  
* 8bc205e Buat beranda toko

Output yang Dihasilkan (perintah git branch -v):

text
  fitur-keranjang 685a343 Isi keranjang
* main            5736882 Gabungkan fitur keranjang dalam satu commit

Riwayat main lurus sempurna — satu commit hasil, tanpa gelembung, tanpa commit berparent dua. fitur-keranjang tetap berdiri sendiri di 685a343; hash pada keluaran mesin pembaca akan berbeda mengikuti commit sungguhan. Teknik meluruhkan riwayat seperti ini juga bisa dicapai lewat rebase interaktif di chapter Menggabungkan Commit .

Pesan Default dan Tabel Opsi #

Pesan merge default menyusun sendiri namanya: Merge branch 'fitur-keranjang' ketika menyatu di main. Saat targetnya bukan main, Git menambahkan tujuan — pada demo arah terbalik tadi pesannya menjadi Merge branch 'main' into fitur-kontak, terlihat pada keluaran git branch -v dan graf. Pesan ini bisa diganti mulus dengan -m, seperti sudah kita lakukan sejak chapter Three-Way Merge . Seluruh kendali penting git merge dirangkum di tabel berikut:

OpsiEfekCocok dipakai saat
-m "pesan"Commit merge langsung dengan pesan ituingin pesan khusus tanpa buka editor
--no-ffPaksa commit penggabung walau fast-forward bisaingin jejak percabangan tetap terlihat
--ff-onlyTolak merge bila fast-forward mustahilmenjaga riwayat tetap lurus
--squashJatuhkan hasil penggabungan ke staging area, tanpa commitingin riwayat linear satu commit per fitur
--abortBatalkan merge yang sedang berjalankonflik atau salah arah, sebelum commit
--continueSelesaikan merge setelah konflik diatasipengganti git commit setelah resolve

--abort dan --continue berperan besar justru saat penggabungan macet total: saat kedua sisi menyunting baris yang sama dan Git berhenti di tengah jalan. Kejadian itu bernama merge conflict, dan chapter berikutnya mereproduksinya persis dari nol: Merge Conflicts .