Praca nad oddziałem w zależności od innego sprawdzanego oddziału

65

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?

sul4bh
źródło
14
Zazwyczaj interfejsy projektu zaplecza powinny być jasno określone. Kiedy więc zaczynasz wdrażanie interfejsu, nie powinno ci to przeszkadzać, jeśli logika zaplecza nadal będzie sprawdzana, ponieważ możesz użyć makiety.
Herr Derb
17
@HerrDerb Och, słodkie letnie dziecko ...
ogrodnik
4
Dlaczego nie możesz napisać tego w stosunku do jeszcze nie sprawdzonego kodu zaplecza?
user253751
Czy Twój zespół ma jakąś uzgodnioną technikę radzenia sobie z tą sytuacją? Jeśli nie, być może powinieneś zgodzić się na coś takiego, ponieważ jest to dość powszechna sytuacja.
Radu Murzea
Nie ma żadnego. Dlatego zadałem to pytanie. Mam bardzo dobre sugestie. Wypróbuję sugestie i zobaczę, jak one się dla mnie sprawdzają.
sul4bh

Odpowiedzi:

42

Czasami mam ten problem. Git jest bardzo elastyczny. Oto jeden ze sposobów, w jaki możesz to zrobić.

Twój pierwszy oddział featureAjest gotowy do przeglądu.

Drugi oddział featureBjest w fazie rozwoju i zależy od kodu w featureAoddziale.

Scal featureAgałąź z featureBgałęzią.

Jeśli wprowadzisz zmiany w featureAgałęzi, powinieneś ponownie połączyć featureAgałąź z featureBgałęzią, aby uwzględnić zmiany.

Powinieneś również najpierw połączyć featureAsię z głównym pniem, w przeciwnym razie, gdy połączysz featureBsię z głównym pniem, przypadkowo również się połączysz featureA. Po featureAscaleniu z głównym pniem możesz pozbyć się featureAgałęzi, ponieważ teraz featureBzależ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ć.

Matt
źródło
To ma sens. Czy to pozwoli na odkręcenie ujednoliceniu featureAna featureBw razie potrzeby?
sul4bh
8
Nie ma operacji cofania, ale jak wspomniano na @ 9000, możesz utworzyć nowy oddział i cherry wybrać z niego wymagane zmiany 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 swojego featureBoddział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 swojego featureBoddziału, jeśli tak się stanie.
Matt
9
Scalenie spowoduje bałagan, który będzie trudny (nie niemożliwy) do wycofania. Zbieram ponownie cherry-pick lub rebase (tj: cherry-pick wszystko w FeatureA u podstawy FeatureB). Zobacz odpowiedź 9000.
Pierre.Sassoulas
1
Stwarza to złożoną historię, która będzie problemem przez wiele lat, ilekroć ktoś chce zrozumieć, jaki kod został zmieniony dla funkcji A i funkcji B
Ian
2
jeśli funkcja A zostanie zaktualizowana, funkcja B powinna być ponownie bazowana, a nie scalona
Lyndon White
39

Poczekaj, pomiń scalanie

W tym podejściu, ty nie chcesz scalić feature_asię feature_bwielokrotnie.

Rebasing został wspomniany w innych odpowiedziach, ale tylko w celu zmiany tego na master. W twoim przypadku chcesz:

  • Zacznij feature_bod feature_a, tj .:

    git checkout feature_a
    git checkout -b feature_b
    
  • Za każdym razem, gdy feature_azmienia się, gdy oczekuje na połączenie master, bazujesz feature_b na nim:

    ... commit something onto feature_a ...
    git checkout feature_b
    git rebase feature_a
    
  • Wreszcie, jak tylko feature_asię połączysz master, po prostu dostajesz nowy masteri bazujesz feature_ana nim po raz ostatni:

    git checkout master
    git pull origin master
    git checkout feature_b
    git rebase --onto master feature_a feature_b
    

    Ten końcowy rebase przeszczepi wszystkie zatwierdzenia, które zwisają od feature_azatwierdzenia (które teraz nie ma znaczenia, ponieważ zostało scalone master) od razu master. Twoja feature_bjest teraz prostą, standardową gałęzią rozpoczynającą się od master.

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; jak feature_ato jest w historii feature_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.

AnoE
źródło
2
Dzięki feature_awielokrotnemu bazowaniu możesz później napotykać problemy, gdy feature_aw międzyczasie sam został bazowany. W wyniku działania git checkout feature_b; git rebase feature_amogą pojawić się konflikty lub zabawne zatwierdzenia zawierające zatwierdzenia przywracające nowe zmiany feature_a. Zwykle można to rozwiązać, używając --interactivei pomijając zatwierdzenia pobrane ze starej wersji drugiego oddziału (ostatnio musiałem to zrobić kilka razy).
maaartinus
@maaartinus, dzięki za heads-up, sam nie spotkałem się z takimi problemami. Podobnie rebasejak wiele innych indywidualnych kroków niż proste merge, z pewnością istnieje znacznie większa szansa na powstanie konfliktu; z drugiej strony mergebyłoby po prostu semantycznie całkiem niewłaściwe w tym przypadku.
AnoE
Myślę, 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.
maaartinus
1
@maaartinus, dodałem mały dodatek na ten temat (aby konsekwentnie wprowadzać zmiany, które muszą przejść do obu gałęzi tylko w gałęzi podstawowej, a nie w dwóch różnych zatwierdzeniach).
AnoE
Niezła technika. Tak też zawsze to robię. git rebase --ontoFTW: D
Radu Murzea
29

Masz 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, masterto pozostać nad nią. Kiedy się masterzmienia, zwykle git fetch origin master:master && git rebase masterznajdujesz 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.

9000
źródło
Ale myślę, że scenariusz jest taki, że funkcja b potrzebuje kodu znajdującego się w funkcji a, rozgałęzienie od master nie będzie bardzo pomocne. Od czego powinienem zacząć Czy powinienem rozgałęziać się z funkcji-a i utrzymywać synchronizację, dopóki funkcja-a nie zostanie ponownie zintegrowana z masterem, a następnie baza z master do cechy-b?
Sinaesthetic
@Sinaesthetic: możesz oczywiście opierać się feature-bna bazie feature-ai wykonywać ją ponownie za każdym razem, gdy feature-asię zmienia. Jest to typowy sposób na zaobserwowanie dużej zmiany: podziel ją na part-A(na podstawie master), part-B(na podstawie part-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.
9000
czy będzie to miało znaczenie, jeśli zmienię part-b z part-a vs. part-b z master pod względem PR? Chcę tylko upewnić się, że moje zmiany nie wyświetlają zmian części a jako zmian części b. Ponadto, jeśli scalę vs. rebase, jak wpłynie to na PR części b? Za każdym razem, gdy myślę, że rozumiem efekty, otrzymuję inny wynik lol
Sinaesthetic
5

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ć.

Ben
źródło
2

Nie widzę tutaj problemu.

Masz to już za każdym razem w masteroddziale, który ciągle się zmienia, podczas gdy funkcje są rozwijane, a następnie łączone.

W konkretnym przykładzie najpierw tworzysz feature_xxx_backendgałąź i rozwijasz zmiany backendu. Gdy to nastąpi, oddział jest gotowy do przeglądu i zostanie scalony masterpo zakończeniu przeglądu.

Tak, po prostu rozpocząć kolejny oddział, feature_yyy_frontend. Prawdopodobnie będziesz chciał rozgałęzić się bezpośrednio feature_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_backendoddział 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 z feature_yyy_frontendoddział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ę na feature_yyy_frontendgałąź 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.

Polygnome
źródło
2

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:

git checkout frontend
git merge backend

lub po prostu

git merge backend frontend

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

Joris Meys
źródło
„Dziwne, że nikt nie wspominał, że można scalić gałąź frontendu z gałąź backendu zamiast z masterami:” Zostało to już wspomniane, np. W mojej własnej odpowiedzi.
Polygnome
@Polygnome frontend nie musi być rozgałęziony bezpośrednio z backendu. Oba mogą być rozgałęzione od mistrza, ale nadal możesz je scalić. Więc twoja odpowiedź tak naprawdę nie wspomina o tym.
Joris Meys
W rzeczywistości moja odpowiedź nie sugeruje, abyś rozgałęział się bezpośrednio z backendu, po prostu twierdzi, że to prawdopodobnie droga do przejścia (ponieważ i tak scalisz te zmiany z gałęzią frontendu).
Polygnome
@Polygnome, wtedy źle zrozumiałem twoją odpowiedź. Zaktualizowano specjalnie dla Ciebie :-)
Joris Meys
Nie wiem, kto głosował za tym, ale proszę, powiedz mi, gdzie się mylę, abym mógł się czegoś nauczyć.
Joris Meys
1

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 featureAi featureB), utwórz PR, który NIE jest przeznaczony do scalenia, ale aby zebrać wczesne informacje zwrotne na temat PoC featureA.

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ć featureAsię 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ć featureBna featureA„s kodu, niezależnie od sposobu wybrania.

Alfa
źródło