Integrasi pada Bagian 2 berjalan mulus karena satu syarat terpenuhi: jalur fitur dan jalur main tidak menyentuh baris yang sama. Bagian ini melanggar syarat itu dengan sengaja — branch fitur/kategori mengganti judul aplikasi, lalu main mengganti judul yang sama dengan teks berbeda — sehingga Git menolak menebak dan merge conflict yang sungguhan harus kita selesaikan. Konflik di sini bukan kecelakaan, melainkan alat latihan: kita membangunnya secara terkontrol supaya penyelesaiannya bisa dipraktikkan dengan tertib, bukan panik.

Menyiapkan Tabrakan Secara Terkontrol #

Fitur kedua, “kategori”, dimulai seperti biasa — branch baru dari main yang kini bertanda v0.1.0:

bash
git switch -c fitur/kategori

Output yang Dihasilkan:

text
Switched to a new branch 'fitur/kategori'

Di branch ini kita melakukan dua suntingan: baris pertama src/app.txt (judul aplikasi) diganti menjadi Aplikasi Catatan Tugas v2, lalu bagian kategori ditambahkan di akhir berkas:

bash
sed -i '1s/.*/Aplikasi Catatan Tugas v2/' src/app.txt
printf '\n## Kategori\n\n- kerja\n- belajar\n- rumah\n' >> src/app.txt
git add src/app.txt
git commit -m "Ganti judul dan tambah kategori tugas"

Output yang Dihasilkan:

text
[fitur/kategori 350ef4a] Ganti judul dan tambah kategori tugas
 1 file changed, 7 insertions(+), 1 deletion(-)

Perintah sed -i '1s/.../.../' mengganti isi baris pertama tanpa menyentuh baris lain. Keadaan berkas di branch:

bash
cat src/app.txt

Output yang Dihasilkan:

text
Aplikasi Catatan Tugas v2
======================

## Daftar Tugas

- [ ] Susun jadwal harian
- [ ] Belajar Git satu jam

## Kategori

- kerja
- belajar
- rumah

main Menyunting Baris yang Sama #

Sekarang giliran main bergerak — dan menyunting baris yang persis sama:

bash
git switch main
sed -i '1s/.*/Aplikasi Tugas Harian/' src/app.txt
git add src/app.txt
git commit -m "Perbarui judul aplikasi"

Output yang Dihasilkan:

text
[main 6946d1b] Perbarui judul aplikasi
 1 file changed, 1 insertion(+), 1 deletion(-)
bash
cat src/app.txt

Output yang Dihasilkan:

text
Aplikasi Tugas Harian
======================

## Daftar Tugas

- [ ] Susun jadwal harian
- [ ] Belajar Git satu jam

Perhatikan keadaan pertabrakan: baris pertama di main berbunyi Aplikasi Tugas Harian, sedangkan baris pertama di fitur/kategori berbunyi Aplikasi Catatan Tugas v2. Dua sisi mengubah baris yang sama dengan isi berbeda — itulah resep konflik konten yang dibahas teorinya di Merge Conflicts .

Git Menolak Menebak #

bash
git merge fitur/kategori

Output yang Dihasilkan:

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

Tiga baris ini adalah anatomi sebuah kegagalan yang tertib:

  1. Auto-merging src/app.txt — Git mencoba menggabungkan sendiri; sebagian besar berkas memang bisa.
  2. CONFLICT (content): Merge conflict in src/app.txt — untuk baris judul, kedua sisi punya versi berbeda dan dasar pencarian tiga arah tidak bisa menentukan pemenang; Git menyerahkan keputusannya kepada kita.
  3. Automatic merge failed; fix conflicts and then commit the result. — merge berhenti di tengah jalan dan keluar dengan exit code 1; tidak ada yang rusak atau hilang, yang ada hanyalah pekerjaan yang menunggu.

Perintah ini memang gagal, dan kegagalannya adalah informasi. Bila kita berubah pikiran di tengah konflik, git merge --abort mengembalikan keadaan pra-merge sepenuhnya — mekanisme penyelamat yang dibahas di Membatalkan Merge .

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 <file>..." to mark resolution)
	both modified:   src/app.txt

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

Dua baris teratas menyatakan merge sedang tertunda: unmerged paths berarti ada berkas yang menunggu keputusan kita. Baris both modified di bagian Unmerged paths menunjuk berkas yang diubah oleh kedua sisi — inilah daftar pekerjaan kita.

Membaca Penanda Konflik #

bash
cat src/app.txt

Output yang Dihasilkan:

text
<<<<<<< HEAD
Aplikasi Tugas Harian
=======
Aplikasi Catatan Tugas v2
>>>>>>> fitur/kategori
======================

## Daftar Tugas

- [ ] Susun jadwal harian
- [ ] Belajar Git satu jam

## Kategori

- kerja
- belajar
- rumah

Tiga penanda menyekat daerah yang bertabrakan:

  • <<<<<<< HEAD hingga ======= — versi pihak kita, yaitu main (posisi HEAD saat merge dimulai): Aplikasi Tugas Harian;
  • ======= hingga >>>>>>> fitur/kategori — versi pihak yang digabungkan: Aplikasi Catatan Tugas v2;
  • baris penanda itu sendiri bukan isi berkas — semuanya harus dihapus sebelum berkas dianggap selesai.

Satu pengamatan penting: bagian ## Kategori sudah berada di berkas tanpa penanda apa pun. Suntingan ujung berkas dari branch berhasil digabung otomatis; hanya baris judul yang tabrakan. Konflik bersifat lokal pada daerah yang bertabrakan, bukan pada seluruh berkas — satu merge bisa memuat beberapa daerah konflik sekaligus, masing-masing diselesaikan sendiri.

Menyelesaikan dengan Empat Langkah Tertib #

Ritual penyelesaiannya empat langkah, urutannya tidak boleh ditukar — sama persis dengan yang dibedah di Menyelesaikan Merge Conflicts :

  1. Baca status — sudah kita lakukan; daerah konflik dan berkasnya sudah terpetakan.
  2. Sunting berkas — putuskan isi final, hapus seluruh penanda.
  3. git add — tandai daerah konflik selesai.
  4. git commit — lahirkan commit merge penyelesaian.

Langkah kedua adalah keputusan, bukan mekanik. Kita memilih Aplikasi Tugas Harian — judul main — dengan alasan domain: akhiran v2 adalah penanda versi yang keliru dipakai sebagai judul, sedangkan nama dari main memang tepat sebagai judul tampil. Konflik selalu diselesaikan dengan alasan seperti ini, bukan dengan memenangkan salah satu sisi begitu saja.

Sunting src/app.txt di editor hingga berisinya:

text
Aplikasi Tugas Harian
======================

## Daftar Tugas

- [ ] Susun jadwal harian
- [ ] Belajar Git satu jam

## Kategori

- kerja
- belajar
- rumah

Kemudian langkah ketiga dan keempat:

bash
git add src/app.txt
git commit -m "Selesaikan konflik judul di src/app.txt"

Output yang Dihasilkan:

text
[main caa6e56] Selesaikan konflik judul di src/app.txt

Keluarannya tampak seperti commit biasa, padahal ini commit merge. Git mengetahui ada MERGE_HEAD yang menunggu, sehingga commit yang dibuat otomatis berparent dua — menggabungkan main dan fitur/kategori sekaligus. Perintah git add di langkah ketiga berperan ganda: dari penanda “berkas konflik” menjadi “berkas selesai”.

Riwayat Dua Sisi #

Bentuk graf setelah penyelesaian:

bash
git log --oneline --graph --decorate

Output yang Dihasilkan:

text
*   caa6e56 (HEAD -> main) Selesaikan konflik judul di src/app.txt
|\  
| * 350ef4a (fitur/kategori) Ganti judul dan tambah kategori tugas
* | 6946d1b Perbarui judul aplikasi
|/  
* 6eb32b4 (tag: v0.1.0) docs: catat fitur daftar tugas
*   4074715 Gabungkan fitur daftar tugas
|\  
| * e64b462 Isi daftar tugas awal
| * 0a15ce0 Tambah kerangka daftar tugas
|/  
* ae67134 Rintis aplikasi catatan tugas

Bacaan grafnya: 350ef4a (sisi branch, kanan) dan 6946d1b (sisi main, kiri) berjalan terpisah lalu bertemu di commit merge caa6e56 berparent dua. Dekorasi (tag: v0.1.0) kini terlihat menempel pada commit changelog — tanda bahwa dua fitur ini tumbuh di atas rilis pertama. Hash di mesin kita berbeda, komposisinya tidak.

Branch fitur/kategori sudah tergabung penuh, jadi bereskan seperti biasa:

bash
git branch -d fitur/kategori

Output yang Dihasilkan:

text
Deleted branch fitur/kategori (was 350ef4a).

Pelajaran dari Tabrakan #

Tiga pelajaran yang layak dibawa dari sesi ini. Pertama, konflik lahir bukan karena “dua branch berubah”, melainkan karena dua branch menyunting daerah yang sama — di sini, baris judul pada kedua sisi; perubahan pada daerah berbeda digabung otomatis tanpa satu pun penanda. Kedua, Git tidak pernah membuang data ketika konflik: kedua versi tersimpan utuh di antara penanda, dan setiap keputusan kita tercatat permanen di commit penyelesaian. Ketiga, ritual empat langkah membuat penyelesaian bisa diaudit — siapa pun yang membaca git show caa6e56 akan melihat bagaimana konflik judul diurai.

Isi aplikasi kini utuh — daftar tugas, kategori, dan judul baru. Masalah terakhir proyek ini bukan isi, melainkan bentuk: fitur berikutnya akan lahir dari eksperimen berantakan yang justru harus tidak dirapikan dulu. Bagian 4 menunjukkan cara melipatnya menjadi satu commit bersih: Bagian 4: Merapikan Riwayat .