Mengapa git tidak menggabungkan garis yang berdekatan tanpa konflik?

25

Saya baru-baru belajar bahwa ketika menggabungkan dua cabang di git, jika ada perubahan pada dua baris yang berdekatan git menyatakan ini sebagai konflik. Misalnya, jika file test.txtmemiliki konten ini:

Line 1: A
Line 2: B
Line 3: C
Line 4: D

dan di cabang masterkita ubah ini menjadi

Line 1: A
Line 2: B1
Line 3: C
Line 4: D

sementara di cabang testingkita ubah ini menjadi

Line 1: A
Line 2: B
Line 3: C1
Line 4: D

dan kemudian mencoba untuk menggabung testingke dalam master, git menyatakan gabungan konflik. Harapan naif saya adalah bahwa merger akan terjadi tanpa konflik dan menghasilkan ini:

Line 1: A
Line 2: B1
Line 3: C1
Line 4: D

Saya yakin ada alasan bagus mengapa git tidak bergabung dengan cara ini. Adakah yang bisa menjelaskan alasan ini?

rlandster
sumber
Hei, aku baru saja memperhatikan ini minggu lalu. Mungkin kami melakukan tutorial yang sama.
detly
5
Kemampuan penggabungan git sebenarnya sangat buruk, IMO
James
@ James, sudahkah Anda mencoba menggunakan algoritme kesabaran? Saya menemukan saya mendapatkan hasil yang lebih baik dengan itu, khususnya ketika berhadapan dengan di mana bakhil dibagi (misalnya meraih satu fungsi tubuh bukan dua) Jika Anda tidak suka git, Anda juga dapat menggunakan git Anda sendiri (lihat blog.wuwon.id.au/2010/09/… untuk contoh).
deterb
1
Akar penyebabnya adalah bahwa git mencoba melakukan penggabungan itu sendiri, alih-alih memfaktorkannya ke alat khusus. Seluruhnya bukan filosofi Unix. Untuk file sumber, Anda sebenarnya dapat menggunakan tata bahasa untuk menentukan perbedaan secara andal.
MSalters
Satu-satunya konteks umum adalah A dan D, jadi mengapa A / C1 / B1 / D tidak menggabungkan yang benar?
Izkata

Jawaban:

13

Dengan asumsi bahwa potongan kode ini

x=0
x+=1 if foo
x+=1 if bar
return x

telah diubah dalam satu cabang menjadi ini

x=0
x+=1 if foo && xyzzy
x+=1 if bar
return x

dan di cabang lain ke dalam ini

x=0
x+=1 if foo
x+=1 if bar && xyzzy
return x

maka saya tidak ingin git menggabungkannya dengan ini

x=0
x+=1 if foo && xyzzy
x+=1 if bar && xyzzy
return x

tanpa membuatku khawatir.

Untuk menghindari menyebabkan masalah seperti itu, git biasanya menolak untuk secara otomatis menggabungkan perubahan menyentuh garis terdekat. Ini memberi Anda kesempatan untuk memverifikasi apakah logika program akan rusak atau tidak.

Contoh ini sepele, tetapi ketika menggabungkan cabang besar risiko konflik "logis" serupa jauh lebih besar. Kadang-kadang saya bahkan ingin konteksnya menjadi lebih besar daripada saat ini.

Arsen7
sumber
5
Tapi itu tidak ada hubungannya dengan itu, cukup tambahkan garis yang tidak berubah antara keduanya dan tiba-tiba git menggabungkan mereka tanpa masalah.
Darkhogg
Ya saya tidak mendapatkan jawaban ini. Anda bisa menggunakan logika yang sama untuk menghindari semua penggabungan otomatis.
Mehrdad
Harus ada garis yang ditarik antara keamanan dan kegunaan. Penggabungan otomatis menanggung risiko merusak aliran program - seperti yang saya coba tunjukkan dalam jawaban -, tetapi jika git hanya menolak untuk menggabungkan apa pun, itu akan menjadi tidak berguna. Pencipta git baru saja memutuskan beberapa konteks, yang akan menangkap sebagian besar kasus "berbahaya". Menambahkan beberapa baris yang tidak berubah (seperti yang ditemukan Darkhogg) membodohi git agar percaya bahwa penggabungan tersebut mungkin aman untuk dilakukan.
Arsen7
11

Apakah ini hanya perilaku git?

Setelah berdiskusi dengan seorang kolega, saya baru mencoba, dan SVN menanganinya tanpa masalah: Anda mendapatkan 2 baris yang dimodifikasi.

Kemampuan gabungan dari beberapa VCS diuji di sini untuk bazaar, darcs, git, dan lincah : https://github.com/mndrix/merge-this

Tampaknya hanya darcs yang berhasil menggabungkan kasus "garis yang berbatasan".

Menerapkan perubahan yang berdekatan ke file bukanlah masalah yang sulit. Saya benar-benar berpikir perilaku ini telah dipilih dengan sengaja.

Mengapa seseorang memutuskan bahwa memodifikasi garis yang berdekatan menghasilkan konflik?

Saya akan berpikir ini untuk memaksa Anda melihatnya .

int max = MAX_ITEMS;
for(unsigned int i = 0; i < max; i++)
    do_stuff(i);

Modif nomor 1, pada master:

int max = MAX_ITEMS/2; // Do stuff only on the first half
for(unsigned int i = 0; i < max; i++)
    do_stuff(i);

Modif nomor 2, digabung dari cabang:

int max = MAX_ITEMS;
for(unsigned int i = 0; i < max/2; i++) // max/2: only on 1st half
    do_stuff(i);

Setelah bergabung, Anda tidak menginginkan itu:

int max = MAX_ITEMS/2; // Do stuff only on the first half
for(unsigned int i = 0; i < max/2; i++) // max/2: only on 1st half
    do_stuff(i);

Melihat perilaku ini sebagai fitur

Anda dapat mengubah perilaku penggabungan git menjadi keuntungan. Ketika Anda perlu menjaga 2 baris konsisten tetapi Anda tidak dapat mendeteksinya (pada waktu kompilasi, di awal tes Anda atau yang lain), Anda dapat mencoba untuk bergabung dengannya.

Tulis ulang ini ...:

for(unsigned int i = 0; i < max; i++)
    r = do_stuff(i);
    // Need to do something else
    do_something_else(r);

...untuk ini:

for(unsigned int i = 0; i < max; i++)
    r = do_stuff(i);
    do_something_else(r); // Need to do something else

Jadi ketika Anda menggabungkan Modif 1 ...:

for(unsigned int i = 0; i < max; i++)
    r = do_stuff(i)/2; // we need only the half
    do_something_else(r); // Need to do something else

... dengan Modif 2 ...:

for(unsigned int i = 0; i < max; i++)
    r = do_stuff(i);
    if(r < 0) // do_stuff can return an error
        handle_error(r);
    do_something_else(r/2); // Need to do something else

..., git akan menghasilkan konflik, dan Anda akan memaksa Anda untuk melihatnya.

ofaurax
sumber
2
Saya hanya akan melanjutkan dan mengatakan bahwa saya pikir jawaban Anda sangat masuk akal, tetapi tergantung pada rumit, implementasi saling mempengaruhi antara kode Anda dan kontrol sumber Anda untuk pemeriksaan kewarasan adalah jalur cepat ke thedailywtf.com. Menggabungkan kode tanpa parser bahasa secara buta adalah upaya terbaik SELALU, dan saya punya beberapa contoh di mana git membantu mengotomatisasi sesuatu yang seharusnya tidak ada dan menghasilkan kode yang bahkan tidak dapat dikompilasi.
Wug
5

Aku kebanyakan menebak, tapi saya pikir itu ada hubungannya dengan baris 2 digunakan sebagai konteks untuk baris 3 perubahan.

Git tidak bisa hanya mengatakan bahwa "Baris dengan C menjadi garis dengan C1" karena mungkin ada baris lain dengan "C", jadi ia mengatakan "Baris dengan C, itu tepat setelah awal file, baris dengan A, dan garis dengan B, sekarang C1 "

Jika "baris dengan B" tidak ada lagi di sana, maka beberapa konteksnya hilang, dan git hanya dapat mengetahui secara kasar ke mana baris baru harus pergi.

Mike Gossmann
sumber
5
itu juga sangat mungkin bahwa C tergantung pada B, sehingga penggabungan naif mungkin menyusahkan bahkan jika git "tahu bagaimana" melakukannya
Lucina
Percayalah, Git hanya "menganggapnya tahu". Git adalah kuburan konsep yang salah, berusaha diluruskan!
user3833732
2

Jawaban yang lain di sini adalah semua tentang hal, tetapi bagi saya ini selalu tampak seperti pembatasan yang tidak perlu.

Seperti orang lain berkata, dalam kasus ini Anda pasti akan tidak ingin Git menggabungkan garis tanpa peringatan.

Tetapi saya masih menginginkan opsi untuk melakukannya secara otomatis, setelah diperingatkan. Jadi saya menulis sopir gabungan git kustom yang bisa menggabungkan konflik pada yang berdekatan (atau individu) garis interaktif:

masukkan deskripsi gambar di sini

Ini menghemat banyak waktu, karena saya mengelola proyek di mana orang sering mengerjakan file yang sama dan refactoring banyak kode.

Skrip tersedia di GitHub di bawah lisensi GPLv3 +. Mungkin Anda akan merasakan manfaatnya:

https://github.com/paulaltin/git-subline-merge

deltacrux
sumber
4
Akankah seseorang pikiran menjelaskan mengapa ini downvoted? Saya cukup baru di sini, jadi jika saya melakukan sesuatu yang salah, saya ingin tahu apa itu sehingga saya bisa menghindarinya di masa depan. Saya menyadari posting saya tidak persis menjawab pertanyaan yang diajukan, tetapi masih relevan dan saya pikir kebanyakan orang yang datang ke sini ingin tahu bukan hanya mengapa git melakukan ini tetapi juga apa yang dapat mereka lakukan tentang hal itu (seperti yang saya lakukan ketika pertama kali mencapai pertanyaan ini dari pencarian Google).
deltacrux
Saya belum mencobanya tetapi saya datang mencari cara untuk mengotomatisasi ini, dan senang menemukannya di sini. Terima kasih :) Anda luar biasa.
Mehrdad
1
Tidak masalah! Saya harap Anda merasa ini berguna, dan silakan tinggalkan umpan balik di Github jika Anda mengalami masalah atau memiliki saran untuk perbaikan. Terima kasih!
deltacrux