Korzystam z Git już od kilku miesięcy przy projekcie z innym deweloperem. Mam kilkuletnie doświadczenie z SVN , więc chyba przynoszę ze sobą dużo bagażu.
Słyszałem, że Git doskonale nadaje się do rozgałęziania i łączenia, a jak dotąd nie widzę tego. Jasne, rozgałęzienie jest bardzo proste, ale kiedy próbuję się połączyć, wszystko idzie do piekła. Teraz jestem przyzwyczajony do tego z SVN, ale wydaje mi się, że właśnie wymieniłem jeden sub-par system wersjonowania na inny.
Mój partner mówi mi, że moje problemy wynikają z chęci połączenia się nie chcąc, i że w wielu sytuacjach powinienem używać bazy zamiast scalania. Oto przykładowy schemat pracy:
clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature
git checkout master
git merge my_new_feature
Zasadniczo utwórz gałąź funkcji, ZAWSZE dokonuj zmiany bazy od głównej do gałęzi i łącz ją z gałęzi z powrotem do głównej. Należy pamiętać, że oddział zawsze pozostaje lokalny.
Oto przepływ pracy, z którym zacząłem
clone remote repository
create my_new_feature branch on remote repository
git checkout -b --track my_new_feature origin/my_new_feature
..work, commit, push to origin/my_new_feature
git merge master (to get some changes that my partner added)
..work, commit, push to origin/my_new_feature
git merge master
..finish my_new_feature, push to origin/my_new_feature
git checkout master
git merge my_new_feature
delete remote branch
delete local branch
Są dwie zasadnicze różnice (tak myślę): zawsze używam scalania zamiast zmiany bazy i wypycham swoją gałąź funkcji (a moja gałąź funkcji zatwierdza) do zdalnego repozytorium.
Moje rozumowanie dla zdalnej gałęzi jest takie, że chcę, aby moja praca była tworzona podczas tworzenia kopii zapasowej. Kopie zapasowe naszego repozytorium są automatycznie tworzone i można je przywrócić, jeśli coś pójdzie nie tak. Mój laptop nie jest lub nie jest tak dokładnie. Dlatego nienawidzę mieć kodu na moim laptopie, który nie jest dublowany gdzie indziej.
Moje rozumowanie dla scalania zamiast rebase jest takie, że scalanie wydaje się standardowe, a rebase wydaje się być funkcją zaawansowaną. Mam przeczucie, że to, co próbuję zrobić, nie jest zaawansowaną konfiguracją, więc zmiana bazy powinna być niepotrzebna. Przeczytałem nawet nową książkę Pragmatic Programming na Git, która obszernie omawia scalanie i prawie nie wspomina o rebase.
W każdym razie śledziłem przebieg pracy w niedawnym oddziale, a kiedy próbowałem połączyć go z powrotem w master, wszystko poszło do piekła. Było mnóstwo konfliktów z rzeczami, które nie powinny mieć znaczenia. Konflikty nie miały dla mnie sensu. Zajęło mi dzień, aby wszystko załatwić, a ostatecznie kulminacją było zmuszenie do zdalnego mistrza, ponieważ mój lokalny mistrz rozwiązał wszystkie konflikty, ale zdalny nadal nie był szczęśliwy.
Jaki jest „prawidłowy” przepływ pracy dla czegoś takiego? Git ma sprawić, że rozgałęzianie i łączenie będzie super łatwe, a ja po prostu tego nie widzę.
Aktualizacja 2011-04-15
To wydaje się być bardzo popularnym pytaniem, więc pomyślałem, że zaktualizuję swoje dwuletnie doświadczenie, odkąd po raz pierwszy zadałem.
Okazuje się, że oryginalny przepływ pracy jest poprawny, przynajmniej w naszym przypadku. Innymi słowy, robimy to i działa:
clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git checkout master
git merge my_new_feature
W rzeczywistości nasz przepływ pracy jest nieco inny, ponieważ mamy tendencję do wykonywania połączeń squashowych zamiast połączeń surowych. ( Uwaga: jest to kontrowersyjne, patrz poniżej. ) To pozwala nam przekształcić całą gałąź funkcji w pojedyncze zatwierdzenie na master. Następnie usuwamy naszą gałąź funkcji. To pozwala nam logicznie konstruować nasze commity na master, nawet jeśli są trochę niechlujne na naszych oddziałach. Oto co robimy:
clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git checkout master
git merge --squash my_new_feature
git commit -m "added my_new_feature"
git branch -D my_new_feature
Kontrowersje związane ze scalaniem squash - jak zauważyło kilku komentatorów, scalanie squash wyrzuci całą historię w gałęzi funkcji. Jak sama nazwa wskazuje, zgniata wszystkie zatwierdzenia w jeden. W przypadku małych funkcji ma to sens, ponieważ skraca je w jednym pakiecie. W przypadku większych funkcji prawdopodobnie nie jest to świetny pomysł, zwłaszcza jeśli twoje indywidualne zatwierdzenia są już atomowe. To naprawdę sprowadza się do osobistych preferencji.
Żądania ściągania Github i Bitbucket (inni?) - jeśli zastanawiasz się, w jaki sposób scalanie / rebase odnosi się do żądań ściągania , zalecam wykonanie wszystkich powyższych kroków, dopóki nie będziesz gotowy, aby ponownie połączyć się z mistrzem. Zamiast ręcznie łączyć się z gitem, akceptujesz PR. Zauważ, że nie spowoduje to scalenia squasha (przynajmniej domyślnie), ale non-squash, non-fast forward jest przyjętą konwencją scalania w społeczności Pull Request (o ile mi wiadomo). W szczególności działa to tak:
clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git push # May need to force push
...submit PR, wait for a review, make any changes requested for the PR
git rebase master
git push # Will probably need to force push (-f), due to previous rebases from master
...accept the PR, most likely also deleting the feature branch in the process
git checkout master
git branch -d my_new_feature
git remote prune origin
Pokochałem Gita i nigdy nie chcę wracać do SVN. Jeśli walczysz, po prostu trzymaj się go, a ostatecznie zobaczysz światło na końcu tunelu.
źródło
rebase
zrozumieniuOdpowiedzi:
„Konflikty” oznaczają „równoległe ewolucje tej samej treści”. Więc jeśli pójdzie „do piekła” podczas scalania, oznacza to, że masz ogromne zmiany w tym samym zestawie plików.
Powodem, dla którego rebase jest lepszy niż scalanie, jest to, że:
Potwierdzam, że poprawny przepływ pracy w tym przypadku (ewolucja wspólnego zestawu plików) najpierw opiera się na bazie, a następnie łączy .
Oznacza to jednak, że jeśli wypchniesz oddział lokalny (ze względu na kopię zapasową), gałąź ta nie powinna być pobierana (ani przynajmniej używana) przez nikogo innego (ponieważ historia zatwierdzeń zostanie przepisana przez kolejne zmiany bazy).
Na ten temat (rebase, a następnie scalanie), barraponto wspomina w komentarzach dwa interesujące posty, oba z randyfay.com :
(podobna technika istnieje dla bazaru )
git push --force
(zamiastgit pull --rebase
na przykład)źródło
TL; DR
Przepływ pracy git rebase nie chroni cię przed ludźmi, którzy źle radzą sobie z rozwiązywaniem konfliktów lub osobami przyzwyczajonymi do przepływu pracy SVN, jak zasugerowano w Unikanie katastrof Git: krwawa historia . Sprawia to, że rozwiązywanie konfliktów jest dla nich bardziej nużące i trudniejsze do odzyskania po złym rozwiązaniu konfliktu. Zamiast tego użyj diff3, aby nie było tak trudne.
Przepływ pracy Rebase nie jest lepszy do rozwiązywania konfliktów!
Jestem bardzo pro-rebase do czyszczenia historii. Jeśli jednak kiedykolwiek dojdę do konfliktu, natychmiast przerywam rebase i zamiast tego dokonuję scalenia! Naprawdę mnie to zabija, że ludzie zalecają przepływ pracy w bazie danych jako lepszą alternatywę dla przepływu pracy łączenia w celu rozwiązania konfliktu (dokładnie o to chodziło w tym pytaniu).
Jeśli pójdzie „wszystko do piekła” podczas scalania, pójdzie „wszystko do piekła” podczas ponownego uruchomienia i potencjalnie o wiele więcej piekła! Dlatego:
Powód 1: Rozwiązywanie konfliktów raz, zamiast raz dla każdego zatwierdzenia
Kiedy dokonujesz zmiany bazy zamiast scalania, będziesz musiał wykonać rozwiązywanie konfliktów maksymalnie tyle razy, ile będziesz musiał zobowiązać się do zmiany bazy, dla tego samego konfliktu!
Prawdziwy scenariusz
Odgałęziam kapitana, aby refaktoryzować skomplikowaną metodę w oddziale. Moja praca refaktoryzacyjna składa się z 15 zatwierdzeń łącznie, gdy pracuję nad refaktoryzacją i przeglądaniem kodu. Część mojego refaktoryzacji polega na naprawianiu mieszanych zakładek i spacji, które były wcześniej w master. Jest to konieczne, ale niestety spowoduje konflikt z każdą zmianą wprowadzoną później do tej metody w trybie master. Rzeczywiście, kiedy pracuję nad tą metodą, ktoś dokonuje prostej, legalnej zmiany tej samej metody w gałęzi master, którą należy połączyć z moimi zmianami.
Kiedy przychodzi czas na połączenie mojej gałęzi z master, mam dwie opcje:
git merge: Mam konflikt. Widzę zmianę, którą wprowadzili, aby opanować i połączyć ją z (końcowym produktem) mojej gałęzi. Gotowy.
git rebase: Mam konflikt z pierwszym zatwierdzeniem. Rozwiązuję konflikt i kontynuuję rebase. Mam konflikt z drugim zatwierdzeniem. Rozwiązuję konflikt i kontynuuję rebase. Mam konflikt z trzecim zatwierdzeniem. Rozwiązuję konflikt i kontynuuję rebase. Mam konflikt z moim czwartym zatwierdzeniem. Rozwiązuję konflikt i kontynuuję rebase. Mam konflikt z moim piątym zatwierdzeniem. Rozwiązuję konflikt i kontynuuję rebase. Mam konflikt z moim szóstym zatwierdzeniem. Rozwiązuję konflikt i kontynuuję rebase. Mam konflikt z siódmympopełnić. Rozwiązuję konflikt i kontynuuję rebase. Mam konflikt z moim ósmym zatwierdzeniem. Rozwiązuję konflikt i kontynuuję rebase. Mam konflikt z dziewiątym zatwierdzeniem. Rozwiązuję konflikt i kontynuuję rebase. Mam konflikt z moim dziesiątym zatwierdzeniem. Rozwiązuję konflikt i kontynuuję rebase. Mam konflikt z moim jedenastym zatwierdzeniem. Rozwiązuję konflikt i kontynuuję rebase. Mam konflikt z moim dwunastym zatwierdzeniem. Rozwiązuję konflikt i kontynuuję rebase. Mam konflikt z moim trzynastym popełnieniem. Rozwiązuję konflikt i kontynuuję rebase. Mam konflikt z moją czternastkąpopełnić. Rozwiązuję konflikt i kontynuuję rebase. Mam konflikt z moim piętnastym zatwierdzeniem. Rozwiązuję konflikt i kontynuuję rebase.
Żartujesz sobie ze mnie, jeśli to twój ulubiony przepływ pracy. Wystarczy tylko wstawić spację, która powoduje konflikt z jedną zmianą dokonaną na wzorcu, a każde zatwierdzenie spowoduje konflikt i musi zostać rozwiązane. Jest to prosty scenariusz z konfliktem tylko białych znaków. Niebiosa zabraniają ci prawdziwego konfliktu związanego z poważnymi zmianami kodu w plikach i musisz rozwiązać to wiele razy.
Przy wszystkich dodatkowych rozwiązywaniu konfliktów, które musisz zrobić, zwiększa to tylko możliwość popełnienia błędu . Ale błędy są w porządku, ponieważ można cofnąć, prawda? Z wyjątkiem oczywiście ...
Powód # 2: Z rebase nie można cofnąć!
Myślę, że wszyscy możemy się zgodzić, że rozwiązanie konfliktu może być trudne, a także że niektórzy ludzie są w tym bardzo źli. Może być bardzo podatny na błędy, dlatego jest tak świetny, że git ułatwia cofanie!
Podczas scalania gałęzi git tworzy zatwierdzenie scalania, które można odrzucić lub zmienić, jeśli rozwiązanie konfliktu pójdzie źle. Nawet jeśli już wysłałeś niepoprawne zatwierdzenie scalania do publicznego / autorytatywnego repozytorium, możesz użyć go
git revert
do cofnięcia zmian wprowadzonych przez scalanie i powtórzenia scalenia poprawnie w nowym zatwierdzeniu scalania.Kiedy zmieniasz gałąź, w prawdopodobnym przypadku, gdy rozwiązanie konfliktu zostanie wykonane nieprawidłowo, jesteś zepsuty. Każde zatwierdzenie zawiera teraz błędne scalenie i nie można po prostu powtórzyć rebase *. W najlepszym wypadku musisz cofnąć się i zmienić każde z zatwierdzonych zobowiązań. Nie śmieszne.
Po zmianie bazy niemożliwe jest ustalenie, co pierwotnie stanowiło część zatwierdzeń, a co zostało wprowadzone w wyniku złego rozwiązania konfliktu.
* Można cofnąć rebase, jeśli możesz wykopać stare referencje z wewnętrznych dzienników git lub jeśli utworzysz trzecią gałąź, która wskazuje na ostatnie zatwierdzenie przed zmianą bazy.
Wyjdź do diabła z rozwiązywania konfliktów: użyj diff3
Weźmy na przykład ten konflikt:
Patrząc na konflikt, nie można powiedzieć, co zmieniła każda gałąź ani jakie było jej zamierzenie. Jest to moim zdaniem największy powód, dla którego rozwiązywanie konfliktów jest mylące i trudne.
diff3 na ratunek!
Kiedy użyjesz diff3, każdy nowy konflikt będzie miał trzecią sekcję, połączonego wspólnego przodka.
Najpierw sprawdź połączonego wspólnego przodka. Następnie porównaj każdą stronę, aby określić zamiar każdej gałęzi. Możesz zobaczyć, że HEAD zmienił EmailMessage na TextMessage. Jego celem jest zmiana klasy używanej na TextMessage, przekazując te same parametry. Możesz również zobaczyć, że intencją gałęzi funkcji jest przekazanie wartości false zamiast wartości true dla opcji: include_timestamp. Aby scalić te zmiany, połącz zamiar obu:
Ogólnie:
Alternatywnie: rozwiązuj ręcznie, stosując zmiany oddziału
Wreszcie, niektóre konflikty są trudne do zrozumienia, nawet z diff3. Dzieje się tak zwłaszcza wtedy, gdy diff znajduje wspólne linie, które nie są semantycznie wspólne (np. Obie gałęzie miały pustą linię w tym samym miejscu!). Na przykład jedna gałąź zmienia wcięcie ciała klasy lub zmienia kolejność podobnych metod. W takich przypadkach lepszą strategią rozdzielczości może być zbadanie zmiany z dowolnej strony scalania i ręczne zastosowanie różnicy do drugiego pliku.
Spójrzmy, jak możemy rozwiązać konflikt w scenariuszu, w którym łączymy się tam,
origin/feature1
gdzie występująlib/message.rb
konflikty.Zdecyduj, czy nasza aktualnie wyewidencjonowana gałąź (
HEAD
lub--ours
), czy gałąź, którą łączymy (origin/feature1
, lub--theirs
), jest prostszą zmianą do zastosowania. Użycie diff z potrójną kropką (git diff a...b
) pokazuje zmiany, które nastąpiły odb
czasu jego ostatniej rozbieżnościa
lub innymi słowy, porównuje wspólnego przodka aib z b.Sprawdź bardziej skomplikowaną wersję pliku. Spowoduje to usunięcie wszystkich znaczników konfliktu i skorzystanie z wybranej strony.
Po sprawdzeniu skomplikowanej zmiany, wyciągnij różnicę prostszej zmiany (patrz krok 1). Zastosuj każdą zmianę z tego pliku różnicowego do pliku powodującego konflikt.
źródło
W moim przepływie pracy bazuję na podstawach w jak największym stopniu (i staram się to robić często. Nie dopuszczenie do nagromadzenia się rozbieżności drastycznie zmniejsza ilość i nasilenie kolizji między oddziałami).
Jednak nawet w przepływie pracy opartym głównie na rebase istnieje miejsce na scalanie.
Przypomnijmy, że scalenie faktycznie tworzy węzeł, który ma dwoje rodziców. Rozważmy teraz następującą sytuację: Mam dwa niezależne branże funkcji A i B, a teraz chcę opracować rzeczy w gałęzi funkcji C, które zależą zarówno od A, jak i B, podczas gdy A i B są sprawdzane.
To, co robię, to:
Teraz gałąź C zawiera zmiany zarówno z A, jak i B, i mogę nadal nad nią rozwijać. Jeśli dokonam zmiany w A, rekonstruuję wykres rozgałęzień w następujący sposób:
W ten sposób mogę właściwie utrzymywać dowolne wykresy rozgałęzień, ale robienie czegoś bardziej złożonego niż opisana powyżej sytuacja jest już zbyt skomplikowane, biorąc pod uwagę, że nie ma automatycznego narzędzia do zmiany bazowania po zmianie rodzica.
źródło
NIE używaj git push origin --mirror POD PRAWIE ŻADNĄ OKOLICZNOŚCIĄ.
Nie pyta, czy jesteś pewien, że chcesz to zrobić, i lepiej bądź pewien, ponieważ spowoduje to usunięcie wszystkich zdalnych gałęzi, które nie znajdują się w lokalnej skrzynce.
http://twitter.com/dysinger/status/1273652486
źródło
Instructions to this machine may lead to unintended consequences, loss of work/data, or even death (at the hands of the sysad). Remember that you are solely responsible for the consequences of your actions
w MOTD.Po przeczytaniu twojego wyjaśnienia mam jedno pytanie: czy to możliwe, że nigdy tego nie zrobiłeś
przed wykonaniem „git rebase / merge master” w gałęzi funkcji?
Ponieważ twoja główna gałąź nie aktualizuje się automatycznie z repozytorium twojego znajomego. Musisz to zrobić za pomocą
git pull origin
. Tj. Może zawsze bazowałbyś na niezmiennym lokalnym oddziale głównym? A potem nadchodzi czas wypychania, wpychasz do repozytorium, które ma (lokalne) zobowiązania, których nigdy nie widziałeś, a zatem wypychanie kończy się niepowodzeniem.źródło
W twojej sytuacji myślę, że twój partner ma rację. Zaletą zmiany bazy jest to, że dla osoby postronnej zmiany wyglądają tak, jakby same przebiegały w czystej kolejności. To znaczy
Nadal możesz nadal wypychać swój prywatny oddział programistyczny do zdalnego repozytorium ze względu na tworzenie kopii zapasowych, ale inni nie powinni traktować tego jako gałęzi „publicznej”, ponieważ będziesz się opierać. BTW, łatwym poleceniem do tego jest
git push --mirror origin
.Artykuł Oprogramowanie do pakowania korzystające z Git wykonuje całkiem niezłą robotę, wyjaśniając kompromisy w łączeniu i przekształcaniu. To trochę inny kontekst, ale zasady są takie same - w zasadzie sprowadza się to do tego, czy twoje gałęzie są publiczne, czy prywatne i jak planujesz zintegrować je z linią główną.
źródło
origin
kopii lustrzanej , powinieneś wykonać kopię lustrzaną do trzeciego repozytorium kopii zapasowych.Ani w partnerach, ani w sugerowanych przepływach pracy nie powinieneś napotkać konfliktów, które nie miały sensu. Nawet jeśli tak, jeśli przestrzegasz sugerowanych przepływów pracy, po rozwiązaniu nie powinno być wymagane „wymuszone” wypychanie. Sugeruje to, że tak naprawdę nie scaliłeś gałęzi, do której naciskałeś, ale musiałeś pchnąć gałąź, która nie była potomkiem odległej końcówki.
Myślę, że musisz dokładnie przyjrzeć się temu, co się stało. Czy ktoś inny mógł (celowo lub nie) przewinąć zdalną gałąź główną między utworzeniem gałęzi lokalnej a punktem, w którym próbowałeś połączyć ją z powrotem z gałęzią lokalną?
W porównaniu do wielu innych systemów kontroli wersji odkryłem, że używanie Git wymaga mniejszej walki z narzędziem i pozwala zająć się problemami, które są fundamentalne dla twoich strumieni źródłowych. Git nie wykonuje magii, więc konfliktowe zmiany powodują konflikty, ale powinno ułatwić pisanie, śledząc pochodzenie popełnienia.
źródło
Z tego, co zaobserwowałem, git merge ma tendencję do oddzielania gałęzi nawet po scaleniu, podczas gdy rebase następnie scalanie łączy je w jedną gałąź. Ten drugi wychodzi o wiele czystszy, podczas gdy w pierwszym łatwiej byłoby dowiedzieć się, które zatwierdzenia należą do której gałęzi, nawet po połączeniu.
źródło
„Nawet jeśli jesteś pojedynczym programistą z zaledwie kilkoma gałęziami, warto przyzwyczaić się do prawidłowego korzystania z bazy i łączenia. Podstawowy schemat pracy będzie wyglądał następująco:
Utwórz nową gałąź B z istniejącej gałęzi A
Dodaj / zatwierdz zmiany w oddziale B
Wycofaj aktualizacje z oddziału A
Scal zmiany z gałęzi B do gałęzi A ”
https://www.atlassian.com/git/tutorials/merging-vs-rebasing/
źródło
W Git nie ma „poprawnego” przepływu pracy. Używaj czegokolwiek, co płynie łodzią. Jeśli jednak ciągle pojawiają się konflikty podczas łączenia oddziałów, może powinieneś lepiej koordynować swoje wysiłki z innymi programistami? Wygląda na to, że oboje edytujecie te same pliki. Uważaj również na słowa kluczowe spacje i subversion (np. „$ Id $” i inne).
źródło
Używam tylko przepływu pracy rebase, ponieważ jest on wizualnie wyraźniejszy (nie tylko w GitKraken, ale także w Intellij i in
gitk
, ale najbardziej polecam ten pierwszy): masz gałąź, pochodzi ona od mistrza i wraca do mistrza . Kiedy schemat będzie czysty i piękny, będziesz wiedział, że nic nigdy nie pójdzie do piekła .Mój obieg pracy jest prawie taki sam jak w twoim, ale z jedną tylko niewielką różnicą:
squash
zobowiązuję się do jednego w moim oddziale lokalnym, zanimrebase
mój oddział wprowadzi najnowsze zmianymaster
, ponieważ:co oznacza, że jeśli masz 15 zatwierdzeń zmieniających tę samą linię co
master
robi, musisz sprawdzić 15 razy, jeśli nie zgniatasz, ale co ma znaczenie, to wynik końcowy, prawda?Cały przepływ pracy to:
Do kasy
master
i pociągnij, aby upewnić się, że masz najnowszą wersjęStamtąd utwórz nowy oddział
Wykonuj tam swoją pracę, możesz dowolnie popełniać kilka razy i pchać się na odległość, bez obaw, bo to twoja gałąź.
Jeśli ktoś powie ci „hej, mój PR / MR został zatwierdzony, teraz jest scalony z master”, możesz je pobrać / wyciągnąć. Możesz to zrobić w dowolnym momencie lub w kroku 6.
Po wykonaniu całej pracy zatwierdź je, a jeśli masz kilka zatwierdzeń, zmiażdż je (wszystkie są twoją pracą i ile razy zmieniasz wiersz kodu, nie ma znaczenia; jedyną ważną rzeczą jest wersja ostateczna). Naciskaj czy nie, to nie ma znaczenia.
Zamówienie na
master
,pull
ponownie, aby upewnić się, że masz najnowsząmaster
w lokalnym. Twój schemat powinien być podobny do tego:Jak widać, jesteś w lokalnym oddziale, który wywodzi się z przestarzałego statusu
master
, podczas gdymaster
(zarówno lokalny, jak i zdalny) posuwa się naprzód ze zmianami twojego kolegi.master
i wybrać „Rebase”; kolejny powód, dla którego mi się podoba). Następnie będziesz lubić:Teraz masz wszystkie zmiany w najnowszym
master
połączeniu ze zmianami w oddziale. Możesz teraz naciskać na swojego pilota, a jeśli naciskałeś wcześniej, będziesz zmuszony naciskać; Git powie ci, że nie możesz po prostu szybko przewinąć do przodu. To normalne, z powodu zmiany bazy zmieniłeś punkt początkowy swojej gałęzi. Ale nie powinieneś się bać: mądrze używaj siły . W końcu pilot jest również twoją gałęzią, więc nie ma to wpływumaster
nawet, jeśli zrobisz coś złego.Utwórz PR / MR i poczekaj, aż zostanie zatwierdzony, więc
master
otrzymasz swój wkład. Gratulacje! Możesz teraz dokonać zakupumaster
, wyciągnąć zmiany i usunąć lokalny oddział, aby wyczyścić schemat. Zdalna gałąź również powinna zostać usunięta, jeśli nie zostanie to zrobione po scaleniu jej w master.Ostateczny schemat jest znów przejrzysty:
źródło