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:
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 -vOutput yang Dihasilkan (perintah git branch -v):
fitur-kontak 0324ae9 Tambah alamat kontak
* main 50420b4 Tambah halaman faqKedua riwayat sudah menyimpang: main berhenti di “Tambah halaman faq”, fitur-kontak berhenti di “Tambah alamat kontak”. Dari main kita gabungkan:
git merge fitur-kontak -m "Gabungkan fitur kontak"Output yang Dihasilkan:
Merge made by the 'ort' strategy.
kontak.md | 1 +
1 file changed, 1 insertion(+)
create mode 100644 kontak.mdDiffstat menyebut kontak.md — berkas milik sisi fitur — karena itulah arah alirannya: masuk ke main. Posisi kedua penunjuk setelahnya:
git branch -vOutput yang Dihasilkan:
fitur-kontak 0324ae9 Tambah alamat kontak
* main 5dba16e Gabungkan fitur kontakmain maju ke commit penggabung baru; fitur-kontak tidak bergerak sedikit pun dari 0324ae9. Grafnya:
git log --oneline --graph --allOutput yang Dihasilkan:
* 5dba16e Gabungkan fitur kontak
|\
| * 0324ae9 Tambah alamat kontak
* | 50420b4 Tambah halaman faq
|/
* a7106b5 Tambah halaman tentang
* 6f13e68 Buat halaman berandaKetika 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:
git switch fitur-kontak
git merge mainOutput yang Dihasilkan:
Merge made by the 'ort' strategy.
situs.md | 1 +
1 file changed, 1 insertion(+)git branch -vOutput yang Dihasilkan:
* fitur-kontak 4342899 Merge branch 'main' into fitur-kontak
main 9fb3deb Tambah halaman faqgit log --oneline --graph --allOutput yang Dihasilkan:
* 4342899 Merge branch 'main' into fitur-kontak
|\
| * 9fb3deb Tambah halaman faq
* | e60db21 Tambah alamat kontak
|/
* 1bc6f5c Tambah halaman tentang
* 6339829 Buat halaman berandaBaca 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:
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-keranjangOutput yang Dihasilkan (perintah git merge --no-ff fitur-keranjang):
Merge made by the 'ort' strategy.
keranjang.md | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 keranjang.mdTiga 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:
git log --oneline --graph --all
git rev-parse main fitur-keranjangOutput yang Dihasilkan (perintah git log --oneline --graph --all):
* 87893ab Merge branch 'fitur-keranjang'
|\
| * 2da05f3 Susun keranjang belanja
|/
* 23e8d5e Tambah baris b
* e219d35 Commit dasarOutput yang Dihasilkan (perintah git rev-parse main fitur-keranjang):
87893ab36b77b072d3692088478b4d5b8aaa077e
2da05f36186422ba334eddd6973f784cb54dc61aHash 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:
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-keranjangOutput yang Dihasilkan (perintah git merge --squash fitur-keranjang):
Squash commit -- not updating HEAD
Automatic merge went well; stopped before committing as requestedBaris 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:
git statusOutput yang Dihasilkan:
On branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: keranjang.mdKedua commit fitur — “Tambah keranjang kosong” dan “Isi keranjang” — kini meringkuk menjadi satu perubahan staged keranjang.md. Kita rangkai jadi satu commit biasa berparent satu:
git commit -m "Gabungkan fitur keranjang dalam satu commit"Output yang Dihasilkan:
[main 5736882] Gabungkan fitur keranjang dalam satu commit
1 file changed, 2 insertions(+)
create mode 100644 keranjang.mdgit log --oneline --graph --all
git branch -vOutput yang Dihasilkan (perintah git log --oneline --graph --all):
* 5736882 Gabungkan fitur keranjang dalam satu commit
* dd4c583 Tambah halaman tentang
| * 685a343 Isi keranjang
| * e334a69 Tambah keranjang kosong
|/
* 8bc205e Buat beranda tokoOutput yang Dihasilkan (perintah git branch -v):
fitur-keranjang 685a343 Isi keranjang
* main 5736882 Gabungkan fitur keranjang dalam satu commitRiwayat 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:
| Opsi | Efek | Cocok dipakai saat |
|---|---|---|
-m "pesan" | Commit merge langsung dengan pesan itu | ingin pesan khusus tanpa buka editor |
--no-ff | Paksa commit penggabung walau fast-forward bisa | ingin jejak percabangan tetap terlihat |
--ff-only | Tolak merge bila fast-forward mustahil | menjaga riwayat tetap lurus |
--squash | Jatuhkan hasil penggabungan ke staging area, tanpa commit | ingin riwayat linear satu commit per fitur |
--abort | Batalkan merge yang sedang berjalan | konflik atau salah arah, sebelum commit |
--continue | Selesaikan merge setelah konflik diatasi | pengganti 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
.