Dlaczego łączenie 3-drogowe jest korzystniejsze od scalania 2-drogowego?

165

Wikipedia twierdzi, że łączenie trójstronne jest mniej podatne na błędy niż scalanie dwukierunkowe i często nie wymaga interwencji użytkownika. Dlaczego tak się dzieje?

Pomocny byłby przykład, w którym łączenie 3-kierunkowe powiedzie się, a scalanie 2-kierunkowe nie powiedzie się.

Johannes Bittner
źródło

Odpowiedzi:

259

Załóżmy, że Ty i Twój znajomy wyewidencjonowaliście plik i wprowadziliście w nim pewne zmiany. Usunąłeś linię na początku, a twój znajomy dodał linię na końcu. Następnie zatwierdził swój plik i musisz scalić jego zmiany w swojej kopii.

Jeśli wykonywałeś dwukierunkowe scalanie (innymi słowy, różnicę), narzędzie mogłoby porównać dwa pliki i zobaczyć, że pierwsza i ostatnia linia są różne. Ale skąd miałoby wiedzieć, co zrobić z różnicami? Czy scalona wersja powinna zawierać pierwszą linię? Czy powinien zawierać ostatnią linię?

Dzięki scaleniu trójstronnemu może porównać dwa pliki, ale może również porównać każdy z nich z oryginalną kopią (zanim którykolwiek z was go zmieni). Więc może zobaczyć, że usunąłeś pierwszą linię, a twój znajomy dodał ostatnią linię. I może wykorzystać te informacje do stworzenia wersji scalonej.

JW.
źródło
- Ale skąd miałoby wiedzieć, co zrobić z różnicami? Nie rozumiem. Jeśli widzi już różnice między dwoma plikami (bez odniesienia do oryginału), dlaczego nie może zastosować obu zmian kolejno w rosnącej kolejności sygnatur czasowych plików? To znaczy: Zaczyna się od zatwierdzonej kopii mojego przyjaciela, przyjmując ją jako (nowy) oryginał (z dodaniem wiersza u góry), a następnie, na wierzchu, stosuje moje lokalne zmiany (usunięcie wiersza na dole).
Harry
7
@Harry Powiedz, że oryginał miał trzy linie (ABC). Zaczyna się od kopii mojego przyjaciela (ABCD) i porównuje ją z moją (BC). Nie widząc oryginału, może pomyśleć, że usunąłem zarówno A, jak i D, a ostateczny wynik powinien być BC.
JW.
80

Ten slajd z prezentacji o konieczności jest interesujący:

obraz slajdu

Podstawowa logika narzędzia do łączenia trójstronnego jest prosta:

  • Porównaj pliki podstawowe, źródłowe i docelowe
  • Zidentyfikuj „porcje” w pliku źródłowym i docelowym:
    • Kawałki, które nie pasują do podstawy
    • Kawałki, które pasują do podstawy
  • Następnie ułóż połączony wynik składający się z:
    • Fragmenty pasujące do siebie we wszystkich 3 plikach
    • Fragmenty, które nie pasują do bazy w źródle lub celu, ale nie w obu
    • Fragmenty, które nie pasują do bazy, ale pasują do siebie (tj. Zostały zmienione w ten sam sposób zarówno w źródle, jak i celu)
    • Symbole zastępcze dla fragmentów powodujących konflikt, które mają być rozwiązane przez użytkownika.

Zwróć uwagę, że „fragmenty” na tej ilustracji są czysto symboliczne. Każdy może reprezentować wiersze w pliku lub węzły w hierarchii, a nawet pliki w katalogu. Wszystko zależy od tego, do czego zdolne jest dane narzędzie do scalania.

Możesz zapytać, jaką przewagę oferuje łączenie 3-stronne w porównaniu z łączeniem 2-drogowym. Właściwie nie ma czegoś takiego jak dwukierunkowe scalanie, tylko narzędzia, które porównują dwa pliki i pozwalają na „scalanie” poprzez wybieranie fragmentów z jednego lub drugiego pliku.
Tylko scalenie trójstronne daje możliwość sprawdzenia, czy fragment jest zmianą w stosunku do początku i czy zmiany powodują konflikt.

VonC
źródło
„czy zmienia konflikt”. - nie łączy 2-way merge (diff) również pokazuje konflikt (chociaż informacje są utracone od źródła konfliktu) /
Vlad
1
Jednak w Git często występuje 4-kierunkowe scalanie, w którym podstawa nie jest taka sama. Nadal 3-drożne scalanie jest lepsze i 2-drożne.
Wernight
@Wernight, czy istnieje 5-kierunkowe scalanie?
Pacerier
@Pacerier Nie o tym wiem, ale tak właśnie dzieje się podczas git cherry-pick lub rebase.
Wernight
Bardzo szczegółowe i przydatne wyjaśnienie
Kaneg
20

Napisałem o tym bardzo szczegółowy post . Zasadniczo nie można śledzić usuwania / dodawania w obie strony, bardzo, bardzo nieproduktywne.

pablo
źródło
@pablo, jeśli dodam funkcję przed X i dodasz inną funkcję po X, a my dokonamy trójstronnego scalenia, narzędzie automatycznie zastosuje obie zmiany. Ale co się dzieje, gdy moja zmiana faktycznie koliduje z twoją zmianą (np. Każdy z nas tworzy nową funkcję o tej samej nazwie funkcji)? W jaki sposób automatyczne połączenie ma wiedzieć, że niektóre z naszych „nudno łatwych” fuzji mogą w rzeczywistości spowodować konflikt ?
Pacerier,
1
Po prostu przeczytaj samouczek i jest dla mnie bardzo pomocny. Czuję się tak samo jak programiści, których opisałeś. Zawsze obawiałem się trójstronnego połączenia.
racl101
3
Proponuję skopiować i wkleić części swojego artykułu. Myślę, że pomoże ci to zdobyć pozytywne głosy i będzie bardziej zgodne z filozofią stackoverflow.
Samuel
Dobry artykuł. Kiedyś lubiłem używać łatek do rebase, gdy widzisz więcej kontekstu i możesz używać edytora i środowiska do sprawdzania rzeczy, jednak w ten sposób jest zbyt dużo ręcznego modyfikowania łatwych rzeczy. Szkoda, że ​​nie ma fajnego sposobu, który łączy dobre części obu
JonnyRaa
20

Scalanie trójstronne, w którym dwa zestawy zmian w jednym pliku podstawowym są scalane podczas ich stosowania, w przeciwieństwie do stosowania jednego, a następnie scalania wyniku z drugim.

Na przykład wprowadzenie dwóch zmian, w których linia jest dodana w tym samym miejscu, można zinterpretować jako dwie zmiany, a nie zmianę jednej linii.

Na przykład

plik a został zmodyfikowany przez dwie osoby, jedną dodającą łosia, drugą dodającą mysz.

#File a
    dog
    cat

#diff b, a
    dog
+++ mouse
    cat

#diff c, a
    dog
+++ moose
    cat

Teraz, jeśli połączymy zestawy zmian podczas ich stosowania, otrzymamy (3-way merge)

#diff b and c, a
    dog
+++ mouse
+++ moose
    cat

Ale jeśli zastosujemy b, to spójrz na zmianę z b na c, będzie wyglądać tak, jakbyśmy po prostu zmienili „u” na „o” (scalanie dwukierunkowe)

    #diff b, c
    dog
--- mouse
+++ moose
    cat
Theo Belaire
źródło