W jaki sposób git pomaga radzić sobie z poniższym scenariuszem:
Mam zadanie podzielone na 2 części: zadanie zaplecza i zadanie interfejsu użytkownika. Zgłaszam żądanie ściągnięcia, aby scalić zmiany backendu i czekam na scalenie (i adres zwrotny). Podczas oczekiwania nie mogę naprawdę pracować nad zmianami interfejsu użytkownika, ponieważ zależy to od zmian zaplecza i nie są one jeszcze dostępne w gałęzi master.
Jaki jest najlepszy sposób na pobranie zmian do gałęzi zmian interfejsu użytkownika z gałęzi zmian interfejsu wewnętrznego, gdy jest on jeszcze sprawdzany?
Odpowiedzi:
Czasami mam ten problem. Git jest bardzo elastyczny. Oto jeden ze sposobów, w jaki możesz to zrobić.
Twój pierwszy oddział
featureA
jest gotowy do przeglądu.Drugi oddział
featureB
jest w fazie rozwoju i zależy od kodu wfeatureA
oddziale.Scal
featureA
gałąź zfeatureB
gałęzią.Jeśli wprowadzisz zmiany w
featureA
gałęzi, powinieneś ponownie połączyćfeatureA
gałąź zfeatureB
gałęzią, aby uwzględnić zmiany.Powinieneś również najpierw połączyć
featureA
się z głównym pniem, w przeciwnym razie, gdy połączyszfeatureB
się z głównym pniem, przypadkowo również się połączyszfeatureA
. PofeatureA
scaleniu z głównym pniem możesz pozbyć sięfeatureA
gałęzi, ponieważ terazfeatureB
zależy to tylko od głównego pnia.Wolę, gdy moje gałęzie funkcji nie zależą od siebie, ale czasem tak jest i trzeba z tym walczyć.
źródło
featureA
nafeatureB
w razie potrzeby?featureA
, jeśli musisz zacząć od nowa. Dobrze jest myśleć o oddziałach Git jako jednorazowych. Są tanie i łatwe, zawsze możesz stworzyć nowy oddział. Możesz nawet utworzyć gałąź testową ze swojegofeatureB
oddziału, jeśli chcesz pobawić się czymś, czego nie byłeś pewien, a następnie złomować go, jeśli to nie zadziała, lub scalić go z powrotem do swojegofeatureB
oddziału, jeśli tak się stanie.Poczekaj, pomiń scalanie
W tym podejściu, ty nie chcesz scalić
feature_a
sięfeature_b
wielokrotnie.Rebasing został wspomniany w innych odpowiedziach, ale tylko w celu zmiany tego na
master
. W twoim przypadku chcesz:Zacznij
feature_b
odfeature_a
, tj .:Za każdym razem, gdy
feature_a
zmienia się, gdy oczekuje na połączeniemaster
, bazujeszfeature_b
na nim:Wreszcie, jak tylko
feature_a
się połączyszmaster
, po prostu dostajesz nowymaster
i bazujeszfeature_a
na nim po raz ostatni:Ten końcowy rebase przeszczepi wszystkie zatwierdzenia, które zwisają od
feature_a
zatwierdzenia (które teraz nie ma znaczenia, ponieważ zostało scalonemaster
) od razumaster
. Twojafeature_b
jest teraz prostą, standardową gałęzią rozpoczynającą się odmaster
.EDYCJA: zainspirowana komentarzami, mała uwaga: jeśli musisz wprowadzić jakieś zmiany, które wpływają na obie funkcje, pamiętaj o wprowadzeniu zmian
feature_a
(a następnie dokonaj zmiany bazy, jak pokazano). Czy nie zrobić to w dwóch różnych zatwierdzeń w obu gałęziach, nawet jeśli może być kuszące; jakfeature_a
to jest w historiifeature_b
, jedna zmiana w dwóch różnych zatwierdzeniach będzie semantycznie niepoprawna i może później prowadzić do konfliktów lub „wskrzeszeń” niechcianego kodu.źródło
feature_a
wielokrotnemu bazowaniu możesz później napotykać problemy, gdyfeature_a
w międzyczasie sam został bazowany. W wyniku działaniagit checkout feature_b; git rebase feature_a
mogą pojawić się konflikty lub zabawne zatwierdzenia zawierające zatwierdzenia przywracające nowe zmianyfeature_a
. Zwykle można to rozwiązać, używając--interactive
i pomijając zatwierdzenia pobrane ze starej wersji drugiego oddziału (ostatnio musiałem to zrobić kilka razy).rebase
jak wiele innych indywidualnych kroków niż prostemerge
, z pewnością istnieje znacznie większa szansa na powstanie konfliktu; z drugiej stronymerge
byłoby po prostu semantycznie całkiem niewłaściwe w tym przypadku.merge
że miałby podobne lub gorsze problemy (konflikt nie jest tak zły, jak wprowadzenie niechcianych zmian). Widzę gałąź jako sekwencję pożądanych zmian poprzedzoną wieloma niepowiązanymi zmianami (logicznie należącymi do innej gałęzi). Kiedy wielokrotnie bazuję na tej samej gałęzi, zawsze usuwam niepowiązane zmiany, ponieważ wiem, że i tak pojawią się (być może w zaktualizowanym kształcie) i działa dobrze.git rebase --onto
FTW: DMasz już gałąź, od której zależy każda gałąź funkcji, i która ciągle się zmienia. To się nazywa
master
.Typowy sposób, aby gałąź funkcji była zsynchronizowana,
master
to pozostać nad nią. Kiedy sięmaster
zmienia, zwyklegit fetch origin master:master && git rebase master
znajdujesz się w katalogu roboczym swojego oddziału.Możesz zrobić to samo z inną gałęzią funkcji: pobieraj ją i bazuj na niej.
Jeśli z jakiegoś powodu będziesz musiał przenieść swoje zmiany do innej gałęzi, możesz wybrać swoje zatwierdzenia, które nigdy nie są mieszane z zatwierdzeniami innych oddziałów.
źródło
feature-b
na baziefeature-a
i wykonywać ją ponownie za każdym razem, gdyfeature-a
się zmienia. Jest to typowy sposób na zaobserwowanie dużej zmiany: podziel ją napart-A
(na podstawiemaster
),part-B
(na podstawiepart-A
) i więcej w razie potrzeby. Następnie poproś o pobranie każdej części, a recenzenci mają łatwiejszy czas na przeglądanie mniejszych, logicznie pogrupowanych elementów.W tym przypadku, gdy zadanie interfejsu użytkownika ma krytyczną zależność od kodu zaplecza, a Ty chcesz rozpocząć pracę z interfejsem, zanim zostanie on sfinalizowany i zaakceptowany w trybie głównym, po prostu uruchomię zadanie interfejsu jako gałąź funkcji, która wychodzi z gałąź backendu, zamiast rozgałęziania frontendu na masterie.
Gałąź funkcji, która żyje wystarczająco długo, musi okazyjnie łączyć zmiany ze wzorca (aby upewnić się, że można pogodzić wszelkie konflikty scalania lub semantyczne w ramach prac deweloperskich nad gałęzią funkcji, a nie w ramach „przeglądu, qa, scalania- proces do opanowania). Robisz to w gałęzi frontonu, a kiedy praca backendu zostanie zaakceptowana do opanowania, otrzymasz wszelkie drobne zmiany, które zostały wprowadzone do backendu w ramach jego przeglądu / akceptacji automatycznie, tą samą drogą, którą zrobiłbyś uzyskać wszelkie inne zmiany kodu na master.
Jeśli okaże się, że gałąź backendu wymaga dużo więcej pracy i nadal zmienia się przez pewien czas, zanim zostanie scalona z masterem (powiedzmy, jeśli podczas przeglądu zostaną wykryte poważne problemy), prawdopodobnie prawdopodobnie chciałbyś wykonywać okresowe połączenia bezpośrednio z gałęzi backendu do gałęzi frontendu (więc nie opieraj całej pracy frontendu na przestarzałym kodzie backendu). Jest to łatwe, jeśli jesteś jedynym programistą, który wykonuje obie funkcje (ponieważ wiesz, czy sam dokonujesz poważnych zmian), ale nawet jeśli obie funkcje są obsługiwane równolegle przez różnych programistów, powinno być dobrze; po prostu musisz pozostać w komunikacji (co i tak byś musiał, jeśli pracujesz nad zadaniami równolegle, w których jedno ma krytyczną zależność od drugiego).
Jeśli okaże się, że cała gałąź zaplecza musi zostać porzucona i nigdy nie zostanie scalona (wygląda na to, że byłaby to dość poważna sprawa, która rzadko by się zdarzyła), wówczas albo wybieracie swoje zobowiązania do nowej gałęzi, która odchodzi od mistrza bez pracy backendu, lub zastosujesz zatwierdzenia wsteczne, które usuwają cały kod backendu do gałęzi frontendu. Ale, jak widzę, bardziej prawdopodobne byłoby zatrzymanie pracy frontendu, dopóki nie zorientujesz się, co zastąpi wyrzucany backend, a następnie zdecydujesz, co robić.
źródło
Nie widzę tutaj problemu.
Masz to już za każdym razem w
master
oddziale, który ciągle się zmienia, podczas gdy funkcje są rozwijane, a następnie łączone.W konkretnym przykładzie najpierw tworzysz
feature_xxx_backend
gałąź i rozwijasz zmiany backendu. Gdy to nastąpi, oddział jest gotowy do przeglądu i zostanie scalonymaster
po zakończeniu przeglądu.Tak, po prostu rozpocząć kolejny oddział,
feature_yyy_frontend
. Prawdopodobnie będziesz chciał rozgałęzić się bezpośredniofeature_xxx_backend
, aby zmiany te były już w twojej branc. następnie po prostu rozwijaj funkcję frontendu, jak gdyby była gałąźmaster
.Kiedy
feature_xxx_backend
oddział zmienia się, np. Ponieważ pojawiają się rzeczy, które pojawiają się podczas przeglądu, które wymagają rozwiązania, po prostu wprowadź te zmiany i połącz je zfeature_yyy_frontend
oddziałem. Następnie kontynuuj na gałęzi frontendu.Po zakończeniu przeglądu gałęzi zaplecza zostaje on scalony
master
. W tym momencie rozsądnie byłoby zmienić bazę nafeature_yyy_frontend
gałąźmaster
, aby recenzenci musieli tylko przejrzeć nowe zmiany, do których przyczynia się ta gałąźmaster
, i nie musieli ponownie sprawdzać zmian wprowadzonych dla backendu (które zostały już zatwierdzone ).Można to również zrobić, gdy masz dwie, trzy lub więcej zależnych gałęzi. Jeśli masz dwie gałęzie cech, od których zależysz, po prostu utwórz gałąź pochodną, która łączy obie cechy. Rozwiń stamtąd, opracuj trzecią cechę, scal obie gałęzie cech po drodze, gdy każda z nich się zmieni. Gdy obie funkcje zostaną wykonane i zostaną scalone z gałęzią pochodną, dokonaj na tej podstawie zmiany lub, jeśli zostaną scalone na master, dokonaj zmiany na master.
Rebasing (jak zasugerowano powyżej) jest naprawdę potężny i pomaga prowadzić czysty rejestr zmian, znacznie ułatwiając przeglądanie.
źródło
Jak wspomniano w Polygnome, możesz faktycznie połączyć gałąź frontendu z gałąź backendu zamiast z masterami. Nawet przy obecnej konfiguracji gałęzi, którą masz teraz, możesz po prostu:
lub po prostu
Pamiętaj jednak, że jeśli zmiany backendu nie zostaną zaakceptowane i potrzeba więcej pracy, będziesz musiał scalić aktualizacje z backendu z frontendem, aby uniknąć konfliktów. Gdy zmiany zostaną zaakceptowane w systemie głównym, możesz zmienić bazę interfejsu użytkownika na system główny, aby pozbyć się zatwierdzeń scalania.
Technicznie rzecz biorąc, możesz również zrobić wszystko z rebase, ale to zepsuje historię zatwierdzeń twojej gałęzi frontendu. Skąd pochodzę, jest to uważane za złą praktykę. YMMV
źródło
Większość odpowiedzi tutaj poprawnie opisuje proces scalania zmian z drugiej gałęzi do pierwszej, ale nie dotyczą one zminimalizowania liczby konfliktów, które mogą być konieczne do rozwiązania.
Ilekroć masz dwa zestawy dużych zmian, które chcesz przejrzeć indywidualnie (jak
featureA
ifeatureB
), utwórz PR, który NIE jest przeznaczony do scalenia, ale aby zebrać wczesne informacje zwrotne na temat PoCfeatureA
.Ludzie będą mogli szybko to sprawdzić (to tylko PoC), a celem jest zweryfikowanie ogólnego projektu lub podejścia.
Następnie możesz kontynuować pracę nad funkcją A, utworzyć dla niej żądanie ściągnięcia oraz rozgałęzić się i pracować nad funkcją B.
Duża różnica polega na tym, że teraz można spodziewać
featureA
się radykalnej zmiany: projekt i podejście zostały już sprawdzone. Przegląd kodu i wymagane zmiany mogą być subtelne i lokalne, a nie „woops, potrzebujesz innego podejścia”. Pozwoli to zminimalizować ilość prac, które trzeba zrobić, aby później scalićfeatureB
nafeatureA
„s kodu, niezależnie od sposobu wybrania.źródło