Czy istnieje różnica między połączeniami w svn w porównaniu do git lub mercurial?

12

Z mojego zrozumienia, SVN jest „łatwy do rozgałęzienia. Trudne do scalenia ”. Dlaczego? Czy jest jakaś różnica, w jaki sposób się łączą?


źródło

Odpowiedzi:

21

Zobacz moją odpowiedź Przepełnienie stosu, aby zobaczyć bardzo konkretną sytuację, w której Mercurial (i Git) łączą się bez problemów i gdzie Subversion przedstawia ci fałszywy konflikt. Sytuacja polega na prostym refaktoryzacji w oddziale, w którym zmieniasz nazwy niektórych plików.

Jeśli chodzi o odpowiedź tdammerów, istnieje wiele nieporozumień:

  • Subversion, Mercurial i Git wszystkie migawki projektu w całym repozytorium ścieżek. Nazywanie ich wersjami , wersjami lub zestawami zmian nie ma znaczenia. Wszystkie są logicznie atomowymi migawkami zestawu plików.

  • Wielkość twoich commits nie ma znaczenia, jeśli chodzi o scalanie. Wszystkie trzy systemy łączą się ze standardowym trójstronnym algorytmem scalania, a dane wejściowe do tego algorytmu są

    • największa wspólna wersja przodka
    • wersja w jednym oddziale
    • wersja na inny oddział

    Nie ma znaczenia, w jaki sposób powstały dwie wersje gałęzi. Możesz użyć 1000 małych zatwierdzeń od wersji przodka, lub możesz użyć 1 zatwierdzenia. Liczy się tylko ostateczna wersja plików. (Tak, to zaskakujące! Tak, wiele przewodników DVCS robi to okropnie źle).

Podnosi także kilka dobrych punktów na temat różnic:

  • Subversion ma pewne „voodoo”, gdzie można scalić z /trunkdo, powiedzmy, /branches/foo. Mercurial i Git nie używają tego modelu - gałęzie są modelowane bezpośrednio w historii. Historia staje się zatem ukierunkowanym grafem acyklicznym zamiast liniowym. Jest to o wiele prostszy model niż ten używany przez Subversion i to odcina wiele narożnych obudów.

  • Możesz łatwo opóźnić scalenie, a nawet pozwolić komuś innemu na jego obsługę. Jeśli hg mergedajesz mnóstwo konfliktów, możesz poprosić o to swojego współpracownika hg pull, a on ma dokładnie taki sam stan. Więc może hg mergei może lepiej radzi sobie z rozwiązywaniem konfliktów niż ty.

    Jest to bardzo trudne w przypadku Subversion, gdzie przed aktualizacją musisz dokonać aktualizacji . Nie możesz po prostu zignorować zmian na serwerze i nadal zatwierdzać swój własny anonimowy oddział. Ogólnie rzecz biorąc, siły Subversion Ci poeksperymentować z kopii roboczej brudny kiedy svn update. Jest to trochę ryzykowne, ponieważ nie zapisałeś żadnych zmian w bezpiecznym miejscu. Git and Mercurial pozwala najpierw zatwierdzić, a następnie zaktualizować i scalić w razie potrzeby.

Prawdziwym powodem, dla którego Git i Mercurial lepiej się łączą niż Subversion, jest kwestia implementacji. Istnieją konflikty nazw, które Subversion po prostu nie może obsłużyć, nawet jeśli jest jasne, jaka jest prawidłowa odpowiedź. Mercurial i Git radzą sobie z nimi łatwo. Ale nie ma powodu, dla którego Subversion również nie poradziłby sobie z nimi - centralizacja z pewnością nie jest powodem.

Martin Geisler
źródło
4
świetna odpowiedź! Głosowałbym dwa razy, gdybym mógł. :) Dodałbym również, że książka SVN, do której się odwołujesz w odpowiedzi SO, wyraźnie przyznaje, że „funkcja śledzenia scalania Subversion ma niezwykle złożoną wewnętrzną implementację ...” - to samo jest całkiem dobrym wskaźnikiem, że ta funkcja jest zawodna
gnat
2
... i nawet przy tak złożonej implementacji nie jest w stanie poprawnie ustalić wspólnego przodka w żadnym prostym przypadku.
Jan Hudec
O opóźnionych połączeniach - nie rozumiem - dzięki SVN mój współpracownik może zaktualizować do / wyewidencjonować łącze, a następnie połączyć się z moim oddziałem.
Gill Bates,
@GillBates: Mówię o sytuacji, w której nie otworzyłeś oddziału dla swojej pracy - kiedy pracujesz trunkw SVN. Za pomocą DVCS możesz dokonywać transakcji bez udostępniania, ale w SVN svn commitbędziesz mieć bezpośredni wpływ na innych, którzy pracują w tym samym oddziale. Nawet jeśli oboje pracujemy w oddziale w SVN, nie mogę wykonać mojej pracy bez konieczności natychmiastowego połączenia się z twoją pracą. To sprawia, że ​​zatwierdzanie jest nieco przerażające - co jest przerażającą właściwością dla systemu kontroli wersji! :-)
Martin Geisler,
6

Podstawowy problem polega na tym, że systemy te reprezentują wersjonowaną strukturę katalogów.

Podstawową koncepcją Subversion, wokół której obraca się cały system, jest wersja (lub, w svn lingo, „wersja”): migawka pliku w pewnym momencie. Tak długo, jak historia jest idealnie liniowa, wszystko jest w porządku, ale jeśli chcesz połączyć zmiany z dwóch niezależnych linii rozwoju, svn musi porównać bieżące wersje obu, a następnie wykonać trójstronne porównanie między ostatnią udostępnioną wersją i dwie wersje głowy. Linie, które wydają się zmienione w jednej głowicy, ale nie w drugiej, można łatwo rozwiązać; linie odchylające się dokładnie w ten sam sposób w obu głowach są twardsze, ale zwykle wykonalne; linie, które różnią się na różne sposoby, powodują, że svn mówi: „Nie mogę tego rozgryźć, człowieku, proszę, rozwiąż to dla mnie”.

Natomiast zestawy zmian ścieżek git i mercurial zamiast wersji. Całe repozytorium jest drzewem zestawów zmian, każdy w zależności od elementu nadrzędnego, gdzie zestaw nadrzędny może mieć dowolną liczbę elementów podrzędnych, a katalog główny drzewa reprezentuje pusty katalog. Innymi słowy, git / hg mówi „najpierw nie miałem nic, potem ta łatka została zastosowana, potem ta łatka itp.”. Kiedy potrzebujesz połączyć dwie linie rozwoju, git / hg nie tylko wie, jak obecnie wygląda każda głowa i jak wyglądała ostatnia wspólna wersja, ale także wie, jak przebiegło przejście, umożliwiając znacznie inteligentniejsze łączenie.

Kolejną rzeczą, która ułatwia łączenie w DVCS, jest pośrednia konsekwencja rozdzielenia koncepcji zatwierdzenia i wypchnięciaoraz zezwalanie na wszelkiego rodzaju połączenia krzyżowe między dowolnymi dwoma klonami tego samego repozytorium w dowolnym momencie. W przypadku svn ludzie mają tendencję do dokonywania dużych zestawów zmian z często niezwiązanymi ze sobą zmianami, ponieważ zatwierdzenie jest także aktualizacją centralnego repozytorium, która wpływa na wszystkich innych członków zespołu; jeśli popełnisz zepsutą wersję, wszyscy będą na ciebie źli. Ponieważ większość konfiguracji wymaga sieciowego serwera svn, zatwierdzanie wiąże się również z pompowaniem danych przez sieć, co oznacza, że ​​zatwierdzenie wprowadza znaczne opóźnienie w przepływie pracy (szczególnie, gdy twoja kopia robocza jest nieaktualna i musisz najpierw pobrać). W przypadku git i mercurial zatwierdzanie odbywa się lokalnie, a ponieważ oba są bardzo wydajne w obsłudze lokalnych systemów plików, zwykle kończy się natychmiast. W rezultacie ludzie (gdy się do tego przyzwyczają) dokonują niewielkich zmian przyrostowych, a następnie, gdy to działa, naciskać kilkanaście zatwierdzeń za jednym razem. Następnie, gdy nadejdzie czas scalania, SCM ma znacznie bardziej szczegółowe informacje i może lepiej i automatycznie rozwiązywać konflikty.

A potem są ładne szczegóły, które jeszcze bardziej ułatwiają:

  • Możesz mieć wiele głów i nadal zatwierdzać oba; w przeciwieństwie do subversion, nie musisz łączyć ściągania, aktualizacji i scalania przed ponownym zatwierdzeniem - wiele głów pozostaje tak długo, dopóki nie wybierzesz scalenia
  • Katalogi nie są traktowane specjalnie; zamiast tego ścieżka jest uważana za jedną dużą nazwę pliku, a wszystkie katalogi muszą być zawsze w tej samej wersji. Oznacza to, że nie możesz robić voodoo z wywrotem, gdzie podfoldery projektu są w różnych wersjach, ale oznacza to również, że kopia robocza ma mniejsze szanse stać się ogromnym, niemożliwym do zarządzania, popsutym bałaganem, a co ciekawe, ruch nie jest reprezentowany jako usunięcie -i-dodaj (co by całkowicie zepsuło się w svn, gdyby nie metadane modernizacyjne), ale po prostu jako zmiana nazwy; jeśli przeniesiesz plik, cała jego historia zostanie zachowana; scalanie może nawet zastosować zmiany do przeniesionego pliku, które zostały wprowadzone w nieprzenoszonej wersji tego samego pliku po przeniesieniu, w innej gałęzi
  • W większości przypadków nie potrzebujesz nawet rozgałęzienia: zamiast tego po prostu klonujesz całe repozytorium. Klonowanie jest tanie, zwłaszcza jeśli odbywa się na tym samym systemie plików, a jeśli zdecydujesz, że chcesz się go pozbyć, po prostu usuń katalog, w którym on mieszka i to wszystko. Nie musisz nawet używać do tego hg ani git.
  • Istnieje kilka (jeśli w ogóle) ograniczeń dotyczących tego, co można scalić. Możesz mieć sześć klonów tego samego repozytorium i łączyć (a raczej pchać lub ciągnąć; jawne scalanie często nie jest wymagane) od A do B, następnie C do B, następnie B do D, a następnie C do D, B z powrotem do A, D do E, w dowolnym momencie i tak często, jak chcesz.
  • Możesz przetestować scalenie, klonując jedno z repozytoriów, które chcesz scalić, a następnie przyciągając je z drugiego. Jeśli zrobi to, co chcesz, możesz odepchnąć się z powrotem do prawdziwego celu, jeśli nie, wyrzuć klon i zacznij od nowa.
tdammers
źródło
2
Muszę wspomnieć o kilku poprawkach i uzupełnieniu odpowiedzi: 1. Wersje SVN są globalne dla repozytorium , wersja reprezentuje w pewnym momencie wszystkie pliki w repo 2. Technologia scalania jest w zasadzie powszechna w SVN i DVCS - jeśli plik w plikach scalania zmienił tylko w ten sam sposób scalanie spowoduje taką samą liczbę konfliktów dla SVN i DVCS - wszystkie SCM nadal działają na poziomie łańcucha, a nie logiczny blok 3. Duże zmiany w SVN nie są wynikiem słabości architektonicznej, ale dlatego, że użytkownicy często są leniwymi idiotami - ignorują podstawowe wzorce. Scalanie gałęzi | działa w SVN, jeśli działa / dev / brain i / dev / hands
Lazy Badger
2
Część 2: Inteligentne scalanie w DVCS najczęściej ma miejsce, ponieważ w przeciwieństwie do Subversion, śledzą i obsługują zmiany nazw plików i SVN wcale tego nie robi, a zatem - każda operacja, która przetwarza plik, zmienia się z jednej strony i zmienia nazwę na po drugie, zawiedzie. Rozgałęzianie z gałęziami i klonowanie to po prostu różne strategie rozgałęziania z tymi samymi prawami do życia, z których można korzystać „... zależy od ...”
Lazy Badger
@LazyBadger: Au contraire. Subversion nie porusza się kolein / zmienia nazwę, co powoduje fałszywych konfliktów częściowo bo to manipulacyjny zmienia nazwę w seryjnej jest po prostu buggy, a częściowo dlatego, że istnieją przypadki, narożne, które są trudne lub niemożliwe do obsługi poprawnie. Późniejsze jest to, dlaczego git (i mercurial skopiował go) z założenia nie śledzi nazw i zgaduje je podczas łączenia. Co działa dobrze, jeśli zawartość jest nadal wystarczająco podobna do scalenia (czyli wtedy, gdy jej potrzebujesz) i nie robi głupich rzeczy inaczej.
Jan Hudec
@JanHudec - przepraszam, uchwyt SVN nie przenosi | zmienia nazwy przy jednej atomowej akcji (sposób DVCS - „zmiana nazwy”), ale jako „usuń + ...”, a zatem - powoduje konflikty drzew, w których nie zdarza się to w DVCS ( prawdziwa zmiana nazwy) ). Mercurial zmienia nazwę ścieżki jawnie ( hg mvlub hg addremove --similarity...), podczas gdy Git używa heurystyki, ale obie obsługują zmiany nazw . Mogę uzyskać konflikt drzewa nawet z różnicą 1 łańcucha w scalonych plikach! Niestety, musisz ponownie nauczyć się niektórych aspektów Subversion.
Lazy Badger
5
Teraz mamy dość techniczne :-) Zarówno kopie utworów Subversion, jak i Mercurial , a nie nazwy. Oba systemy śledzenia rename a b, jak copy a b; remove ai zarówno to zrobić w jeden popełnić atomowej. Różnica w zachowaniu podczas scalania wynika z odmiennej obsługi przypadków narożnych oraz z Subversion, która pozwala na więcej połączeń niż Mercurial i Git. Wreszcie, Git wykrywa zmiany nazw podczas scalania i rejestrowania - myślimy o dodaniu tego również w Mercurial.
Martin Geisler,