Często czytam, że Hg (i Git i ...) są lepsze w łączeniu niż SVN, ale nigdy nie widziałem praktycznych przykładów, gdzie Hg / Git może scalić coś, gdzie SVN zawodzi (lub gdzie SVN wymaga ręcznej interwencji). Czy mógłbyś opublikować kilka list krok po kroku operacji rozgałęzień / modyfikacji / zatwierdzeń /...-, które pokazują, gdzie SVN zawiedzie, podczas gdy Hg / Git szczęśliwie rusza dalej? Praktyczne, niezbyt wyjątkowe przypadki proszę ...
Trochę tła: mamy kilkudziesięciu programistów pracujących nad projektami wykorzystującymi SVN, z każdym projektem (lub grupą podobnych projektów) w swoim własnym repozytorium. Wiemy, jak zastosować gałęzie wydania i funkcji, więc nie napotykamy zbyt często problemów (tj. Byliśmy tam, ale nauczyliśmy się przezwyciężyć problemy Joela dotyczące „jednego programisty powodującego traumę dla całego zespołu” lub „potrzeba sześciu programistów na dwa tygodnie w celu ponownej integracji oddziału”). Mamy gałęzie wydania, które są bardzo stabilne i używane tylko do naprawiania błędów. Mamy trunki, które powinny być wystarczająco stabilne, aby móc utworzyć wydanie w ciągu tygodnia. Mamy też gałęzie funkcji, nad którymi mogą pracować pojedynczy programiści lub grupy programistów. Tak, są usuwane po ponownej integracji, aby nie zaśmiecały repozytorium. ;)
Więc wciąż próbuję znaleźć zalety Hg / Git nad SVN. Chciałbym zdobyć praktyczne doświadczenie, ale nie ma jeszcze żadnych większych projektów, które moglibyśmy przenieść na Hg / Git, więc utknąłem z graniem z małymi sztucznymi projektami, które zawierają tylko kilka zmyślonych plików. I szukam kilku przypadków, w których można poczuć imponującą moc Hg / Git, ponieważ do tej pory często o nich czytałem, ale nie udało mi się ich znaleźć.
Odpowiedzi:
Sam nie używam Subversion, ale z informacji o wydaniu Subversion 1.5: Śledzenie scalania (podstawowe) wygląda na to, że istnieją następujące różnice w stosunku do tego, jak działa śledzenie scalania w systemach kontroli wersji z pełnym DAG , takich jak Git lub Mercurial.
Łączenie magistrali do gałęzi różni się od łączenia gałęzi do gałęzi: z jakiegoś powodu łączenie magistrali do gałęzi wymaga
--reintegrate
opcjisvn merge
.W rozproszonych systemach kontroli wersji, takich jak Git czy Mercurial, nie ma technicznej różnicy między główną a gałęzią: wszystkie gałęzie są sobie równe ( choć mogą istnieć różnice społeczne ). Scalanie w dowolnym kierunku odbywa się w ten sam sposób.
Musisz podać opcję new
-g
(--use-merge-history
)svn log
isvn blame
wziąć pod uwagę śledzenie scalania.W Git i Mercurial śledzenie scalania jest automatycznie uwzględniane podczas wyświetlania historii (dziennika) i winy. W Git możesz poprosić o śledzenie tylko pierwszego rodzica
--first-parent
(myślę, że podobna opcja istnieje również dla Mercurial), aby „odrzucić” informacje o śledzeniu scalania wgit log
.Z tego, co rozumiem,
svn:mergeinfo
właściwość przechowuje informacje o konfliktach dla poszczególnych ścieżek (Subversion opiera się na zestawie zmian), podczas gdy w Git i Mercurial jest to po prostu zatwierdzanie obiektów, które mogą mieć więcej niż jednego rodzica.Podsekcja „Znane problemy” dotycząca śledzenia scalania w Subversion sugeruje, że powtarzane / cykliczne / refleksyjne scalanie może nie działać poprawnie. Oznacza to, że przy następujących historiach drugie scalanie może nie przynieść właściwego efektu („A” może oznaczać linię główną lub gałąź, a „B” może oznaczać odpowiednio gałąź lub linię główną):
W przypadku, gdy powyższa grafika ASCII zostanie zerwana: gałąź `` B '' jest tworzona (rozwidlana) z gałęzi `` A '' w wersji `` x '', a później gałąź `` A '' jest scalana w wersji `` y '' do gałęzi `` B '' jako scal 'M1', a na koniec gałąź 'B' jest połączona z gałęzią 'A' jako scalenie 'M2'.
W przypadku, gdy powyższa grafika ASCII zostanie zerwana: gałąź „B” jest tworzona (rozwidlana) z gałęzi „A” w wersji „x”, jest scalana do gałęzi „A” w pozycji „y” jako „M1”, a później ponownie połączone w gałąź „A” jako „M2”.
Subversion może nie obsługiwać zaawansowanych przypadków scalania krzyżowego .
Git radzi sobie dobrze z tą sytuacją w praktyce, używając strategii scalania „rekurencyjnego”. Nie jestem pewien co do Mercurialu.
W sekcji „Znane problemy” jest ostrzeżenie, że śledzenie scalania może nie działać ze zmianami nazw plików, np. Gdy jedna strona zmienia nazwę pliku (i być może modyfikuje go), a druga strona modyfikuje plik bez zmiany nazwy (pod starą nazwą).
Zarówno Git, jak i Mercurial radzą sobie dobrze z takim przypadkiem w praktyce: Git wykorzystujący wykrywanie zmian nazwy , Mercurial wykorzystujący śledzenie zmian nazw .
HTH
źródło
<pre>...</pre>
bloku nie jest wcięta tak, jak powinno ...--reintegrate
jest przestarzałe.Ja również szukałem przypadku, w którym, powiedzmy, Subversion nie łączy gałęzi, a Mercurial (i Git, Bazaar, ...) postępuje właściwie.
Książka SVN opisuje, w jaki sposób pliki o zmienionych nazwach są nieprawidłowo scalane . Dotyczy to Subversion 1.5 , 1.6 , 1.7 i 1.8 ! Próbowałem odtworzyć poniższą sytuację:
Według książki scalanie powinno zakończyć się czysto, ale z błędnymi danymi w pliku o zmienionej nazwie, ponieważ
trunk
zapomniano o aktualizacji . Zamiast tego pojawia się konflikt drzewa (to jest z Subversion 1.6.17, najnowszą wersją Debiana w momencie pisania):W ogóle nie powinno być konfliktu - aktualizacja powinna zostać wkomponowana w nową nazwę pliku. Podczas gdy Subversion kończy się niepowodzeniem, Mercurial obsługuje to poprawnie:
Przed scaleniem repozytorium wygląda następująco (z
hg glog
):Wynik scalenia to:
Innymi słowy: Mercurial wziął zmianę z wersji 1 i połączył ją z nową nazwą pliku z wersji 2 (
hello.en.txt
). Obsługa tego przypadku jest oczywiście niezbędna do obsługi refaktoryzacji, a refaktoryzacja jest dokładnie tym, co chcesz zrobić w gałęzi.źródło
Nie wspominając o zwykłych zaletach (zatwierdzenia offline, proces publikacji , ...) oto przykład „scalania”, który mi się podoba:
Główny scenariusz, który ciągle widzę, to gałąź, na której ... faktycznie powstają dwa niepowiązane zadania
(zaczęło się od jednej funkcji, ale doprowadziło do rozwoju drugiej funkcji.
Lub zaczęło się od poprawki, ale prowadziło do rozwój innej cechy).
Jak połączyć tylko jedną z dwóch funkcji w głównej gałęzi?
Albo jak wyodrębnić te dwie funkcje w ich własnych gałęziach?
Możesz spróbować wygenerować jakieś poprawki, problem polega na tym, że nie jesteś już pewien funkcjonalnych zależności, które mogły istnieć między:
Git (i przypuszczam, że Mercurial też) proponuje opcję rebase --onto do rebase (resetowania katalogu głównego gałęzi) części gałęzi:
Z postu Jefromiego
możesz rozwikłać tę sytuację, w której masz łatki dla v2, a także nową funkcję wss na:
, umożliwiając:
Inną funkcją, która mi się podoba (która wpływa na scalenie), jest możliwość zgniatania zatwierdzeń (w gałęzi, która nie została jeszcze przeniesiona do innego repozytorium) w celu przedstawienia:
Zapewnia to dużo łatwiejsze połączenia i mniej konfliktów.
źródło
Niedawno przeprowadziliśmy migrację z SVN do GIT i stanęliśmy w obliczu tej samej niepewności. Było wiele anegdotycznych dowodów na to, że GIT był lepszy, ale trudno było znaleźć jakiekolwiek przykłady.
Mogę jednak powiedzieć, że GIT jest DUŻO LEPSZY w łączeniu niż SVN. To oczywiście anegdota, ale jest tabela, której należy przestrzegać.
Oto kilka rzeczy, które znaleźliśmy:
Podczas oceny GIT przeprowadziliśmy następujące testy. Pokazują one GIT jako zwycięzcę, jeśli chodzi o łączenie, ale nie aż tak bardzo. W praktyce różnica jest znacznie większa, ale wydaje mi się, że nie udało nam się odtworzyć sytuacji, z którymi SVN radzi sobie źle.
źródło
Inni omówili bardziej teoretyczne aspekty tego. Może mógłbym podać bardziej praktyczną perspektywę.
Obecnie pracuję dla firmy, która używa SVN w modelu rozwoju „gałęzi funkcji”. To jest:
Ogólnie to działa. SVN może być użyty do takiego przepływu, ale nie jest doskonały. Istnieją pewne aspekty SVN, które przeszkadzają i kształtują ludzkie zachowanie. To daje pewne negatywne aspekty.
^/trunk
. Te mioty łączą rekordy informacyjne w całym drzewie i ostatecznie przerywają śledzenie scalania. Zaczynają się pojawiać fałszywe konflikty i panuje zamieszanie.svn merge
robi co chcesz. Scalanie zmian z powrotem wymaga (powiedziano nam)--reintegrate
polecenia scalania. Nigdy tak naprawdę nie rozumiałem tego przełącznika, ale oznacza to, że gałęzi nie można ponownie połączyć z linią główną. Oznacza to, że jest to martwa gałąź i musisz utworzyć nową, aby kontynuować pracę. (Patrz uwaga)Zwykle zdarza się, że inżynier tworzy gałąź pierwszego dnia. Rozpoczyna pracę i zapomina o niej. Jakiś czas później przychodzi szef i pyta, czy może przenieść swoją pracę do bagażnika. Inżynier bał się tego dnia, ponieważ reintegracja oznacza:
... a ponieważ inżynier robi to tak mało, jak tylko może, nie pamiętają „magicznego zaklęcia”, które należy wykonać na każdym kroku. Zdarzają się niewłaściwe przełączniki i adresy URL i nagle są w bałaganie i idą po „eksperta”.
W końcu wszystko się uspokaja, a ludzie uczą się, jak radzić sobie z niedociągnięciami, ale każdy nowy starter ma te same problemy. Ostateczna rzeczywistość (w przeciwieństwie do tego, co przedstawiłem na początku) to:
...ale...
Na szczęście zespół jest wystarczająco mały, aby sobie z tym poradzić, ale nie da rady. Chodzi o to, że nic z tego nie jest problemem w CVCS, ale co więcej, ponieważ połączenia nie są tak ważne, jak w DVCS, nie są tak sprytne. To „tarcie przy scalaniu” powoduje zachowanie, co oznacza, że model „gałęzi funkcji” zaczyna się rozpadać. Dobre połączenie musi być cechą wszystkich VCS, a nie tylko DVCS.
Zgodnie z tym istnieje teraz
--record-only
przełącznik, który może być użyty do rozwiązania--reintegrate
problemu, i najwyraźniej v1.8 automatycznie wybiera, kiedy wykonać ponowną integrację i nie powoduje późniejszej martwej gałęziźródło
Przed Subversion 1.5 (jeśli się nie mylę), Subversion miał znaczną wadę, ponieważ nie pamiętał historii scalania.
Spójrzmy na przypadek przedstawiony przez VonC:
Zwróć uwagę na wersje A i B. Powiedzmy, że scaliłeś zmiany z wersji A w gałęzi „wss” do gałęzi „tylko v2” w wersji B (z dowolnego powodu), ale nadal korzystałeś z obu gałęzi. Jeśli spróbujesz ponownie scalić dwie gałęzie za pomocą merkurialu, scaliłoby to tylko zmiany po wersjach A i B. W przypadku Subversion musiałbyś scalić wszystko, tak jakbyś wcześniej nie dokonał scalenia.
To jest przykład z mojego własnego doświadczenia, w którym łączenie się z B do A zajęło kilka godzin ze względu na ilość kodu: ponowne przejście przez to byłoby naprawdę trudne , co miałoby miejsce w przypadku subversion przed 1.5.
Kolejna, prawdopodobnie bardziej istotna różnica w zachowaniu podczas łączenia z Hginit: reedukacja Subversion :
Krótko mówiąc, sposób analizowania różnic przez Mercurial jest (był?) Lepszy od metody wywrotowej.
źródło