Jedną z zalet korzystania z DVCS jest przepływ pracy edycji-zatwierdzania-scalania (w stosunku do edycji-scalania-zatwierdzania często wymuszanej przez CVCS). Zezwalanie na rejestrowanie każdej unikalnej zmiany w repozytorium niezależnie od fuzji zapewnia, że DAG dokładnie odzwierciedla prawdziwy rodowód projektu.
Dlaczego tak wiele witryn mówi o tym, że chcą „uniknąć zatwierdzeń scalania”? Czy połączenie scalania przed zatwierdzeniem lub zmiany po scaleniu nie utrudnia izolacji regresji, przywracania wcześniejszych zmian itp.?
Wyjaśnienie: Domyślne zachowanie DVCS polega na tworzeniu zatwierdzeń scalania. Dlaczego tak wiele miejsc mówi o chęci zobaczenia historii rozwoju liniowego, która ukrywa te zobowiązania do scalania?
version-control
git
dvcs
merging
Jace Browning
źródło
źródło
git pull
)? Rozumiem, dlaczego może to być problematyczne, ale moje pytanie dotyczy wszystkich zatwierdzeń scalania.git pull --rebase == svn up
(luźno-równa, nie ścisła-równa)Odpowiedzi:
Ludzie chcą uniknąć zatwierdzania scalania, ponieważ sprawia, że dziennik jest ładniejszy. Poważnie. Wygląda na scentralizowane dzienniki, z którymi dorastali, i lokalnie mogą cały swój rozwój w jednym oddziale. Nie ma żadnych korzyści oprócz tych estetycznych, a oprócz tych, o których wspomniałeś, ma kilka wad, takich jak skłonność do konfliktów, aby wyciągać bezpośrednio od kolegi bez przechodzenia przez „centralny” serwer.
źródło
W dwóch słowach:
git bisect
Liniowa historia pozwala wskazać rzeczywiste źródło błędu.
Przykład. To jest nasz początkowy kod:
Oddział 1 dokonuje pewnych refaktoryzacji, które
arg
nie są już ważne:Oddział 2 ma nową funkcję, z której należy korzystać
arg
:Nie będzie żadnych konfliktów scalania, jednak wprowadzono błąd. Na szczęście ten konkretny zostanie złapany na etapie kompilacji, ale nie zawsze mamy tyle szczęścia. Jeśli błąd przejawia się jako nieoczekiwane zachowanie, a nie błąd kompilacji, możemy go nie znaleźć przez tydzień lub dwa. W tym momencie
git bisect
na ratunek!O kurcze. Oto, co widzi:
Więc kiedy wyślemy,
git bisect
aby znaleźć zatwierdzenie, które złamało kompilację, wskaże zatwierdzenie scalenia. Cóż, to trochę pomaga, ale zasadniczo wskazuje na pakiet zatwierdzeń, a nie na jeden. Wszyscy przodkowie są zieleni. Z drugiej strony, dzięki rebasingowi otrzymujesz liniową historię:Teraz
git bisect
wskaże dokładnie zatwierdzenie funkcji, które złamało kompilację. Idealnie, komunikat zatwierdzenia wyjaśni, co było wystarczająco dobre, aby zrobić kolejny refaktor i naprawić błąd od razu.Efekt jest spotęgowany tylko w dużych projektach, gdy opiekunowie nie napisali całego kodu, więc niekoniecznie pamiętają, dlaczego dane zatwierdzenie zostało wykonane / po co była każda gałąź. Tak więc ustalenie dokładnego zatwierdzenia (a następnie możliwość sprawdzenia zatwierdzeń wokół niego) jest wielką pomocą.
Mimo to (obecnie) nadal wolę scalanie. Przejście na gałąź wydania zapewni Ci liniową historię do wykorzystania
git bisect
, przy jednoczesnym zachowaniu prawdziwej historii do codziennej pracy.źródło
gitk --all
niezwykle przydatna jest możliwość obserwowania przepływu zatwierdzeń między gałęziami (zwłaszcza, że zwykle mam 3-gałęziowe gałęzie w danym momencie i przełączam się między nimi każdego dnia, w zależności od mojego nastroju w czas).bisect
wyniku. Łatwo jest znaleźć poszczególne zatwierdzenia z innymblame
lub innym,bisect
jeśli chcesz kopać głębiej. W przypadku historii liniowej scalanie odbywa się poza księgą, więc nie można już stwierdzić, że problem polegał na złym scaleniu. Wygląda to jak idiota używający argumentu, który nie istnieje, zwłaszcza jeśli argument został usunięty kilka poprzednich zatwierdzeń. Próbowanie dowiedzieć się, dlaczego to zrobił, jest znacznie trudniejsze, gdy niszczysz historię.Krótko mówiąc, ponieważ łączenie jest często innym miejscem, w którym coś może się nie udać, i musi tylko raz pójść nie tak, aby ludzie bardzo bali się poradzić sobie z tym ponownie (raz ugryziony dwukrotnie, jeśli chcesz).
Załóżmy, że pracujemy nad nowym ekranem zarządzania kontem, i okazuje się, że w przepływie pracy nowego konta wykryto błąd. OK, bierzemy dwie oddzielne ścieżki - kończysz zarządzanie kontem, a ja naprawiam błąd w nowych kontach. Ponieważ oboje mamy do czynienia z kontami, pracowaliśmy z bardzo podobnym kodem - być może musieliśmy nawet dostosować te same fragmenty kodu.
W tej chwili mamy dwie różne, ale w pełni działające wersje oprogramowania. Obaj przeprowadziliśmy zatwierdzenie naszych zmian, oboje sumiennie przetestowaliśmy nasz kod i niezależnie jesteśmy bardzo pewni, że wykonaliśmy świetną robotę. Co teraz?
Czas połączyć się, ale ... cholera, co się teraz stanie? Możemy równie dobrze przejść od dwóch działających zestawów oprogramowania do jednego, zunifikowanego, okropnie zepsutego fragmentu nowo błędnego oprogramowania, w którym zarządzanie kontem nie działa, a nowe konta są zepsute, a ja nawet nie wiem, czy nadal występuje stary błąd .
Być może oprogramowanie było inteligentne i powiedziało, że wystąpił konflikt, i nalegaliśmy, abyśmy udzielili mu wskazówek. Cóż, cholera - siadam, aby to zrobić i widzę, że dodałeś złożony kod, którego od razu nie rozumiem. Myślę, że jest to sprzeczne ze zmianami, które wprowadziłem ... Pytam, a kiedy masz minutę, sprawdzasz i widzisz mój kod, którego nie rozumiesz. Jedno lub oboje z nas musi poświęcić trochę czasu, aby usiąść, odpowiednio przygotować połączenie i być może ponownie przetestować całą sprawę, aby upewnić się, że jej nie złamaliśmy.
Tymczasem 8 innych facetów popełnia kod, tak jak są sadystami, zrobiłem kilka drobnych poprawek i przesłałem je, zanim zdałem sobie sprawę, że mamy konflikt scalania, a mężczyzna z pewnością wydaje się, że to dobry moment na przerwę, a może ty są wolne po południu lub utknęły na spotkaniu lub czymkolwiek. Może powinienem wziąć urlop. Lub zmień kariery.
Aby uciec przed tym koszmarem, niektórzy ludzie bardzo boją się zaangażowania (co nowego, amiright?). Naturalnie ryzykujemy awersję w takich scenariuszach - chyba że uważamy, że jesteśmy do dupy i i tak to spieprzymy, w takim przypadku ludzie zaczną działać z lekkomyślnym porzuceniem. westchnienie
Więc proszę bardzo. Tak, nowoczesne systemy zostały zaprojektowane w celu złagodzenia tego bólu, i powinien on być w stanie łatwo wycofywać się i bazować, obniżać i freebase i hanglide i tak dalej.
Ale to wszystko więcej pracy, a my po prostu chcemy nacisnąć przycisk na kuchence mikrofalowej i zrobić 4-daniowy posiłek, zanim zdążymy znaleźć widelec, i wszystko to wydaje się bardzo niespełnione - kod jest pracą, jest produktywny, jest znaczący, ale z wdziękiem obsługa scalania po prostu się nie liczy.
Programiści z reguły muszą rozwinąć świetną pamięć roboczą, a następnie mają tendencję do natychmiastowego zapominania o wszystkich śmieciach i nazwach zmiennych oraz określaniu zakresu, gdy tylko zakończą problem, i radzą sobie z konfliktem scalania (lub, co gorsza, źle wykonane połączenie) jest zaproszeniem do przypomnienia o twojej śmiertelności.
źródło
Rebasing zapewnia ruchomy punkt rozgałęzienia, który upraszcza proces wypychania zmian z powrotem do linii bazowej. Pozwala to traktować długo działającą gałąź jak lokalną zmianę. Bez zmiany zasad gałęzie gromadzą zmiany od linii bazowej, które zostaną uwzględnione w połączonych zmianach z powrotem do linii bazowej.
Scalenie pozostawia linię bazową w oryginalnym punkcie rozgałęzienia. Jeśli połączysz kilka tygodni zmian z linii, z której się rozgałęziłeś, masz teraz wiele zmian w punkcie rozgałęzienia, z których wiele będzie w linii podstawowej. Utrudnia to identyfikację zmian w oddziale. Przesunięcie zmian z powrotem do linii bazowej może powodować konflikty niezwiązane z wprowadzonymi zmianami. W przypadku konfliktów możliwe jest wprowadzanie niespójnych zmian. Trwające fuzje wymagają zarządzania, a zmiany są stosunkowo łatwe.
Rebase przenosi punkt rozgałęzienia do najnowszej wersji na linii bazowej. Wszelkie napotkane konflikty będą dotyczyły wyłącznie Twoich zmian. Wprowadzanie zmian jest znacznie prostsze. Konflikty są rozwiązywane w lokalnym oddziale poprzez wykonanie dodatkowej bazy. W przypadku sprzecznych wypychań ostatni, który wypchnie ich zmianę, będzie musiał rozwiązać problem ze swoją zmianą.
źródło
Zautomatyzowane narzędzia stają się coraz lepsze w zapewnianiu, że scalający się kod będzie się kompilował i działał, unikając w ten sposób konfliktów składniowych , ale nie mogą zagwarantować braku logicznych konfliktów, które mogą zostać wprowadzone przez scalenia. Tak więc „udane” scalenie daje poczucie fałszywej pewności, podczas gdy w rzeczywistości nic nie gwarantuje, a ty musisz powtórzyć wszystkie testy.
Prawdziwy problem z rozgałęzianiem i scalaniem, tak jak to widzę, polega na tym, że przysłania przysłowiową puszkę. Pozwala powiedzieć „Po prostu będę pracować w moim własnym małym świecie” przez tydzień i rozwiążę wszelkie problemy, które pojawią się później. Ale naprawianie błędów jest zawsze szybsze / tańsze, gdy są świeże. Zanim wszystkie gałęzie kodu zaczną się scalać, możesz już zapomnieć o niuansach rzeczy, które zostały wykonane.
Weź oba wyżej wymienione problemy razem, a możesz znaleźć się w sytuacji, w której łatwiej i łatwiej jest sprawić, aby wszyscy pracowali z tego samego tułowia i stale rozwiązywać konflikty, gdy pojawiają się, nawet jeśli spowalniają aktywny rozwój.
źródło
Dodatkowym istotnym punktem jest to, że: poprzez zmianę wersji mogę łatwo wybrać lub przywrócić funkcję w mojej gałęzi wydania.
źródło
git cherry-pick -x <commit>
zastosujemy go do gałęzi wydania. Lub, możemy chcieć cofnąć coś w tej wersji, używającgit revert <commit>
. Jeśli<commit>
jest to scalenie, staje się owłosione. Jest to możliwe, o ile wiem, ale niełatwe. Kiedy używasz rebase, każde „scalenie” jest jednym gigantycznym, ale regularnym zatwierdzeniem, łatwo cherr-do pobrania i odwracalne.W żadnej z odpowiedzi nie powiedziano trzech rzeczy:
Różnicowanie wewnątrz gałęzi:
Scalanie jednego elementu na raz:
Czyszczenie przed wypchnięciem:
źródło