Git neden bitişik çizgileri çatışma olmadan birleştirmiyor?


25

Geçenlerde git iki şubesini birleştirirken, iki bitişik satırda değişiklik varsa git'in bunun bir çatışma olduğunu ilan ettiğini öğrendim . Örneğin, eğer test.txtbu dosya içeriğe sahipse:

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

ve masterbiz dalda bunu değiştiririz.

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

testingbiz daldayken bunu değiştiririz.

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

ve sonra bir araya getirme girişiminde testingiçine master, git bir birleştirme çakışma beyan eder. Saf beklentim, birleşmenin çatışma olmadan gerçekleşmesi ve şunu vermesi idi:

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

Git'in bu şekilde birleşmemesinin iyi bir nedeni olduğuna eminim. Birisi bu nedeni açıklayabilir mi?


Hey, bunu geçen hafta da farkettim. Belki aynı öğreticiyi yapıyorduk.
zorla

5
git'in birleştirme yetenekleri aslında oldukça zayıf, IMO
James

@James, sabır algoritmasını kullanmayı denediniz mi? Özellikle topakların bölündüğü yerlerle uğraşırken daha iyi sonuçlar elde ettiğimi biliyorum (örneğin, iki yerine bir işlev gövdesini kapma). Git'i beğenmiyorsanız , kendinizinkini de kullanabilirsiniz ( örneğin, blog.wuwon.id.au/2010/09/… ).
deterb

1
Kök sebep, git'in uzman bir araca ayırmak yerine, birleştirme işlemini gerçekleştirmeye çalışmasıdır. Tamamen Unix felsefesi değil. Kaynak dosyalar için, farkları güvenilir bir şekilde belirlemek için dil gramerini kullanabilirsiniz.
MSalters

Tek ortak bağlam A ve D'dir, öyleyse neden A / C1 / B1 / D doğru birleştirme değil?
Izkata

Yanıtlar:


13

Bu kod snippet'ini varsayarak

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

bir şubede buna dönüştürüldü

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

ve buna başka bir dalda

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

o zaman git'in bunu birleştirmek istemem

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

beni korkutmadan.

Bu gibi sorunlara neden olmamak için, git genellikle yakındaki çizgilere dokunarak değişiklikleri otomatik olarak birleştirmeyi reddeder. Program mantığının kırılıp kırılmadığını doğrulama şansı verir.

Bu örnek önemsizdir, ancak büyük dalları birleştirirken benzer "mantıksal" çatışmaların riski çok daha büyüktür. Bazen bağlamı şu anda olduğundan daha büyük olmasını bile isterim.


5
Bununla bir ilgisi yok, ancak, basitçe bu ikisi arasına değişmeyen bir çizgi ekleyin ve git git bir problem yaşamadan birleşiyor.
Darkhogg

Evet bu cevabı anlamadım. Tüm otomatik birleşmelerden kaçınmak için aynı mantığı kullanabilirsiniz.
Mehrdad

Güvenlik ve fayda arasında çizilen bir çizgi olmalı. Otomatik birleşmeler, program akışını bozma riskini taşır - cevapta göstermeye çalıştığım gibi - ancak git bir şeyi birleştirmeyi reddederse, işe yaramaz hale gelirdi. Git'in yaratıcıları, “tehlikeli” olayların çoğunu yakalayacak bazı bağlamlara karar vermişlerdir. Değişmeyen bir çizgi eklemek (Darkhogg'un öğrendiği gibi), birleşmenin gerçekleştirilmesinin güvenli olacağına inanmaya yöneltir.
Arsen7,

11

Bu sadece git davranışı mı?

Bir meslektaşımla tartıştıktan sonra az önce denedim ve SVN sorunsuz bir şekilde ele alıyor : 2 satır değiştirilmiş.

Birkaç VCS'nin birleştirme yetenekleri burada pazar, darcs, git ve mercurial için test edilmiştir : https://github.com/mndrix/merge-this

Görünüşe göre sadece darcs "bitişik çizgiler" davasını başarıyla birleştiriyor

Dosyalara bitişik değişiklikler uygulamak zor bir sorun değildir. Gerçekten bu davranışın bilerek seçildiğini düşünüyorum.

Neden biri bitişik çizgileri değiştirmenin bir çelişki yarattığına karar veriyor?

Bunun sizi bakmaya zorlamak olduğunu düşünüyorum .

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

Değişiklik numarası 1, ana birimde:

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

Bir daldan birleştirilmiş 2 numaralı değişiklik:

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

Birleşmeden sonra bunu istemezsin:

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);

Bu davranışı bir özellik olarak görme

Git birleştirme davranışını bir avantaja dönüştürebilirsiniz. 2 çizgiyi tutarlı tutmanız gerektiğinde ancak tespit edemiyorsanız (derleme zamanında, testlerinizin başında veya başka bir durumda), onlara katılmayı deneyebilirsiniz.

Bunu yeniden yaz ...:

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

...buna:

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

Yani Modif 1'i birleştirdiğinizde ...:

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

... Modif 2 ile ...:

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 bir çatışmaya neden olacak ve siz de ona bakmaya zorlayacaksınız.


2
Ben sadece devam edeceğim ve cevabınızın son derece makul olduğunu düşünüyorum, ancak karmaşıklığa bağlı olarak, kodunuzla akıl kontrolü için kaynak kontrolünüz arasındaki uygulama tanımlı etkileşim thedailywtf.com için hızlı bir yoldur. Bir dil ayrıştırıcısı olmadan kodu kör bir şekilde birleştirmek HER ZAMAN en iyi gayrettir ve git'in sahip olmaması gereken bir şeyi otomasyona sokması ve derlemeyecek bir kod üretmesi için birkaç örneğim oldu.
Wug

5

Çoğunlukla tahmin ediyorum, ancak satır 2 değişikliği için bağlam olarak kullanılan satır 2 ile ilgili olduğunu düşünüyorum.

Git, "C'nin C ile bir satırı haline geldiğini" söyleyemez çünkü "C" ile başka bir satır olabilir, yani "C ile satır, dosyanın başlangıcından hemen sonra A ve B'nin çizgisi şimdi C1 "

Eğer "B'li çizgi" artık orada değilse, bağlamın bir kısmı kaybolur ve git sadece kabaca yeni çizginin nereye gideceğini söyler.


5
C'nin B'ye bağlı olması da çok muhtemeldir, bu yüzden git bir "nasıl yapılacağını" bilse bile, saf bir birleşme zahmetli olabilir
Lucina 12

İnan bana Git sadece "bildiğini sanıyor". Git, yanlış kavramların bir mezarlığı, düzeltilmeye çalışılıyor!
user3833732

2

Buradaki diğer cevapların hepsi açık, ama bana bu her zaman gereksiz bir sınırlama gibi geldi.

Diğerlerinin de söylediği gibi, bu durumlarda Git'in kesinlikle çizgileri uyarmadan birleştirmek istemezsiniz.

Ancak yine de uyarıldıktan sonra otomatik olarak yapma seçeneğini istedim. Bu yüzden komşu (veya bireysel) hatlardaki çatışmaları etkileşimli olarak birleştirebilecek özel bir git birleştirme sürücüsü yazdım:

görüntü tanımını buraya girin

İnsanların çoğu kez aynı dosyalar üzerinde çalıştığı ve çok sayıda kodu yeniden düzenlediği bir projeyi yönettiğim için bana çok fazla zaman kazandırıyor.

Komut GitHub'da GPLv3 + lisansı altında mevcuttur. Belki yararlı bulabilirsiniz:

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


4
Birisi bunun neden reddedildiğini açıklayabilir mi? Burada oldukça yeniyim, bu yüzden yanlış bir şey yaptıysam ne olduğunu bilmek isterdim, gelecekte de bundan kaçınabileyim. Mesajımın sorulan soruyu tam olarak cevaplamadığını fark ettim, ama yine de alakalı ve buraya gelenlerin çoğunun sadece Git'in neden yaptığını değil, aynı zamanda bu konuda ne yapabildiklerini de bilmek istiyorum. bu soruya önce Google’dan bir arama ile ulaşıldı).
deltacrux 12:18

Henüz denemedim, ancak bunu otomatikleştirmek için bir yol aradım ve burada bulduğuma memnun oldum. Teşekkürler :) harikasın.
Mehrdad

1
Sorun değil! Umarım yararlı bulursunuz ve sorun yaşarsanız ya da iyileştirme konusunda önerileriniz varsa lütfen Github hakkında geri bildirim bırakmaktan çekinmeyin. Teşekkürler!
deltacrux
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.