Konflik di chapter sebelumnya meninggalkan satu pertanyaan terbuka: versi mana yang benar? Bagian ini menjawabnya dengan empat langkah yang menjadi ritual setiap pengembang Git — baca status, sunting berkas, git add, commit — lalu menutup dengan dua situasi khas: mengambil satu sisi penuh dengan git checkout --ours/--theirs, dan konflik yang lahir dari tabrakan hapus-versus-sunting yang penandanya berbeda. Semua keluaran di bawah hasil eksekusi sungguhan pada Git 2.47.3; alurnya identik di mesin pembaca, dengan hash yang berbeda-beda.

Membangun Ulang Konflik Latihan #

Kita pakai skenario yang sama dengan chapter Merge Conflicts : kedua branch mengubah baris kontak README.md, dan fitur-kontak menambah panduan.md:

bash
mkdir latihan-selesai && cd latihan-selesai
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf '# Toko Budi\n\nKontak: [email protected]\n' > README.md
git add README.md
git commit -m "Buat README toko"
git switch -c fitur-kontak
printf '# Toko Budi\n\nKontak: [email protected]\n' > README.md
git add README.md
git commit -m "Ganti kontak ke layanan pelanggan"
printf '# Panduan\n1. pilih produk\n' > panduan.md
git add panduan.md
git commit -m "Tambah panduan belanja"
git switch main
printf '# Toko Budi\n\nKontak: [email protected]\n' > README.md
git add README.md
git commit -m "Ganti kontak ke tim penjualan"
git merge fitur-kontak

Output yang Dihasilkan (perintah git merge fitur-kontak):

text
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.

Langkah pertama tetap git status: daftar Unmerged paths dengan status both modified adalah pekerjaan yang menunggu. Pada latihan ini isinya satu berkas saja — README.md.

Sunting Berkas, Pilih atau Gabungkan #

Penyelesaian konflik dimulai di editor, bukan di perintah Git. Tiga pilihan berdiri di meja: ambil versi main (penjualan@), ambil versi fitur-kontak (cs@), atau gabungkan keduanya. Latihan ini memilih jalan ketiga — matriks gabungan — dengan membuang seluruh penanda dan menulis ulang bagian kontak:

bash
printf '# Toko Budi\n\nKontak: [email protected]\nKontak cadangan: [email protected]\n' > README.md
cat README.md

Output yang Dihasilkan (perintah cat README.md):

text
# Toko Budi

Kontak: [email protected]
Kontak cadangan: [email protected]

Tidak ada lagi <<<<<<<, =======, atau >>>>>>> — keputusan sudah tertulis di dalam berkas. Pola pilih-gabung ini bekerja pada teks apa pun; kuncinya satu: hasil akhir harus berisi yang kita mau, bukan sisa marka mesin.

Tandai Selesai lalu Commit #

Suntingan belum dihitung Git sebagai penyelesaian — statusnya masih unmerged sampai dinyatakan selesai lewat git add:

bash
git add README.md
git status

Output yang Dihasilkan (perintah git status):

text
On branch main
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:
	modified:   README.md
	new file:   panduan.md

Baris All conflicts fixed but you are still merging. menegaskan posisi: semua konflik beres, namun merge belum ditutup — perintah penutupnya tinggal satu. Git bahkan sudah menyiapkan draf pesan commit di berkas internal MERGE_MSG:

bash
cat .git/MERGE_MSG

Output yang Dihasilkan (perintah cat .git/MERGE_MSG):

text
Merge branch 'fitur-kontak'

# Conflicts:
#	README.md

Drafnya berisi Merge branch 'fitur-kontak' berikut catatan berkas yang pernah konflik — itulah pesan yang terlihat di editor ketika git commit dijalankan tanpa -m. Kita pakai pesan yang lebih jelas:

bash
git commit -m "Selesaikan konflik kontak di README"

Output yang Dihasilkan:

text
[main 29a75cc] Selesaikan konflik kontak di README
bash
git log --oneline --graph --all

Output yang Dihasilkan:

text
*   29a75cc Selesaikan konflik kontak di README
|\  
| * 5797c4b Tambah panduan belanja
| * e098a09 Ganti kontak ke layanan pelanggan
* | 771cdc6 Ganti kontak ke tim penjualan
|/  
* dad4a8f Buat README toko

Grafnya persis bentuk three-way merge: commit penyelesaian 29a75cc berparent dua di puncak main. Commit ini sekaligus jawaban dari git merge --continue — perintah kembar git commit yang lebih disiplin: ia menolak berjalan bila tidak ada merge yang menunggu atau bila masih ada berkas unmerged. Rincian kedua perintah ini di dokumen resmi git-scm.com/docs/git-merge .

Jalan Pintas: Mengambil Satu Sisi Penuh #

Ketika satu sisi memang layak menang mutlak, suntingan manual bisa dilewati. Repository ketiga menyiapkan dua berkas yang sama-sama konflik — README.md dan pesan.txt:

bash
mkdir latihan-ours && cd latihan-ours
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf '# Toko Budi\n\nKontak: [email protected]\n' > README.md
printf 'Promo hari ini: gratis ongkir\n' > pesan.txt
git add README.md pesan.txt
git commit -m "Buat README dan pesan promo"
git switch -c fitur-promo
printf '# Toko Budi\n\nKontak: [email protected]\n' > README.md
printf 'Promo hari ini: diskon 20 persen\n' > pesan.txt
git add README.md pesan.txt
git commit -m "Perbarui kontak dan promo"
git switch main
printf '# Toko Budi\n\nKontak: [email protected]\n' > README.md
printf 'Promo hari ini: gratis ongkir di atas Rp100 ribu\n' > pesan.txt
git add README.md pesan.txt
git commit -m "Sesuaikan kontak dan promo"
git merge fitur-promo

Output yang Dihasilkan (perintah git merge fitur-promo):

text
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Auto-merging pesan.txt
CONFLICT (content): Merge conflict in pesan.txt
Automatic merge failed; fix conflicts and then commit the result.

Keputusannya: README.md memihak main, pesan.txt memihak fitur-promo. Satu perintah masing-masing:

bash
git checkout --ours README.md
git checkout --theirs pesan.txt

Output yang Dihasilkan (perintah git checkout --ours README.md):

text
Updated 1 path from the index

Output yang Dihasilkan (perintah git checkout --theirs pesan.txt):

text
Updated 1 path from the index

Isi kedua berkas setelah diambil:

bash
cat README.md
cat pesan.txt

Output yang Dihasilkan (perintah cat README.md):

text
# Toko Budi

Kontak: [email protected]

Output yang Dihasilkan (perintah cat pesan.txt):

text
Promo hari ini: diskon 20 persen

Namanya perlu dihafal karena mudah tertukar: --ours selalu berarti branch aktif saat merge (main), --theirs branch yang dibawa masuk (fitur-promo) — persis makna HEAD dan fitur-promo pada penanda konflik. Satu jebakan: perintah ini tidak menandai penyelesaian:

bash
git status --short

Output yang Dihasilkan:

text
UU README.md
UU pesan.txt

Kode UU pada kedua berkas berarti masih unmerged — git add tetap wajib sebelum commit:

bash
git add README.md pesan.txt
git merge --continue

Output yang Dihasilkan (perintah git merge --continue, editor pesan diterima apa adanya):

text
[main 293441f] Merge branch 'fitur-promo'
bash
git log --oneline --graph --all

Output yang Dihasilkan:

text
*   293441f Merge branch 'fitur-promo'
|\  
| * eb96da2 Perbarui kontak dan promo
* | ff1dd57 Sesuaikan kontak dan promo
|/  
* 88e2569 Buat README dan pesan promo

Konflik Hapus versus Sunting #

Varian terakhir tidak menyisakan penanda <<<<<<< sama sekali. Skenarionya: satu sisi menghapus berkas, sisi lain menyuntingnya. Repository keempat menyiapkan pesan etalase yang dihapus oleh fitur-bersih tetapi diperbarui oleh main:

bash
mkdir latihan-moddel && cd latihan-moddel
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf 'Pesan lama: toko tutup setiap Senin\n' > pesan.txt
git add pesan.txt
git commit -m "Tulis pesan etalase"
git switch -c fitur-bersih
git rm pesan.txt
git commit -m "Buang pesan etalase lama"
git switch main
printf 'Pesan lama: toko buka setiap hari\n' > pesan.txt
git add pesan.txt
git commit -m "Perbarui isi pesan etalase"
git merge fitur-bersih

Output yang Dihasilkan (perintah git merge fitur-bersih):

text
CONFLICT (modify/delete): pesan.txt deleted in fitur-bersih and modified in HEAD.  Version HEAD of pesan.txt left in tree.
Automatic merge failed; fix conflicts and then commit the result.

Jenisnya terbaca di kurung: modify/delete — dihapus di fitur-bersih, disunting di HEAD. Penanda <<<<<<< tidak muncul karena tidak ada dua teks yang bisa dipajang berdampingan; yang ada satu pertanyaan: berkas ini boleh hidup atau tidak. Statusnya pun berbeda:

bash
git status

Output yang Dihasilkan:

text
On branch main
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add/rm <file>..." as appropriate to mark resolution)
	deleted by them: pesan.txt

no changes added to commit (use "git add" and/or "git commit -a")

Baris deleted by them: pesan.txt dan petunjuk git add/rm menuntun dua penyelesaian: git add pesan.txt berarti berkas dipertahankan dengan isi versi main, git rm pesan.txt berarti penghapusan diterima. Latihan ini mempertahankannya:

bash
git add pesan.txt
git commit -m "Pertahankan pesan hasil pembaruan"

Output yang Dihasilkan (perintah git commit -m "Pertahankan pesan hasil pembaruan"):

text
[main 92a58ac] Pertahankan pesan hasil pembaruan
bash
git log --oneline --graph --all

Output yang Dihasilkan:

text
*   92a58ac Pertahankan pesan hasil pembaruan
|\  
| * 1526a6c Buang pesan etalase lama
* | b2ebb8e Perbarui isi pesan etalase
|/  
* 15282a0 Tulis pesan etalase

Empat langkah itu menuntaskan hampir semua konflik. Untuk tabrakan besar — belasan berkas, ratusan baris — menyunting manual mulai terasa berat, dan di situlah git mergetool masuk: Merge Tools .