nie można pushować do gałęzi po rebase


133

Używamy git i mamy gałąź master i gałęzie deweloperskie. Muszę dodać nową funkcję, a następnie zmienić bazę zatwierdzeń na master, a następnie wypchnąć master na serwer CI.

Problem polega na tym, że jeśli mam konflikty podczas rebase, nie mogę wysłać do mojej zdalnej gałęzi programisty (na Github) po zakończeniu rebase, dopóki nie ściągnę mojej zdalnej gałęzi. Powoduje to zduplikowane zatwierdzenia. Gdy nie ma konfliktów, działa zgodnie z oczekiwaniami.

pytanie: jak zsynchronizować lokalne i zdalne gałęzie dewelopera bez tworzenia zduplikowanych zatwierdzeń po zmianie bazy i rozwiązaniu konfliktu

Ustawiać:

// master branch is the main branch
git checkout master
git checkout -b myNewFeature

// I will work on this at work and at home
git push origin myNewFeature

// work work work on myNewFeature
// master branch has been updated and will conflict with myNewFeature
git pull --rebase origin master

// we have conflicts
// solve conflict
git rebase --continue

//repeat until rebase is complete
git push origin myNewFeature

//ERROR
error: failed to push some refs to 'git@github.com:ariklevy/dropLocker.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

// do what git says and pull
git pull origin myNewFeature

git push origin myNewFeature

// Now I have duplicate commits on the remote branch myNewFeature

EDYTOWAĆ

Wygląda więc na to, że przerwie to przepływ pracy:

developer1 pracujący nad myNewFeature developer2 pracujący nad hisNewFeature obaj używają mastera jako głównej gałęzi

developer2 łączy myNewFeature z hisNewFeature

developer1 ponownie bazuje, rozwiązuje konflikty, a następnie wymusza wypychanie do zdalnego oddziału dla myNewFeature

kilka dni później developer2 ponownie łączy myNewFeature z jegoNewFeature

Czy to spowoduje, że inni deweloperzy znienawidzą programistę Developer1?


nie rozwiązanie, ale tylko myśl. kto we? czy jesteś w zespole złożonym z czegoś więcej niż tylko ty? theypowiedz (ludziom, którzy wiedzą więcej niż ja), że jeśli udostępniasz swój kod, nie powinieneś go używać rebase. Dlaczego po prostu nie robisz git pulli git merge?
AdamT

przepraszam, We = zespół programistów
Matt

1
więc tak, prawdopodobnie nie powinno się zmieniać bazy podczas udostępniania kodu. co może sprawić, że będziesz musiał robić takie rzeczy, jak wymienione poniżej ( forcenacisk)
AdamT

och przepraszam, kiedy mówią rewriting history, to jestrebase
AdamT

Jak powiedział, jest to jego własna gałąź rozwojowa, więc nie powinno to stanowić problemu, chyba że ktoś miał to scalić.
Learath2,

Odpowiedzi:


94

Po pierwsze, ty i ci, z którymi pracujesz, musicie ustalić, czy gałąź tematyczna / rozwojowa jest przeznaczona do wspólnego rozwoju, czy tylko do twojego. Inni programiści wiedzą, że nie powinni łączyć się w moich gałęziach programistycznych, ponieważ w dowolnym momencie zostaną ponownie utworzeni. Zwykle przepływ pracy wygląda następująco:

o-----o-----o-----o-----o-----o       master
 \
   o-----o-----o                      devel0
                \
                  o-----o-----o       devel1

Następnie, aby być na bieżąco z pilotem, wykonam następujące czynności:

 git fetch origin
 git checkout master
 git merge --ff origin/master

Robię to z dwóch powodów. Po pierwsze, ponieważ pozwala mi sprawdzić, czy są zdalne zmiany bez konieczności przełączania się z mojej gałęzi rozwojowej. Po drugie, jest to mechanizm bezpieczeństwa, który zapewnia, że ​​nie nadpisuję żadnych niezachowanych / zatwierdzonych zmian. Ponadto, jeśli nie mogę szybko połączyć się z główną gałęzią, oznacza to, że ktoś zmienił bazę zdalnego mastera (za co musi zostać poważnie chłostany) lub przypadkowo zdecydowałem się na master i muszę wyczyścić mój koniec.

Następnie, gdy pilot ma zmiany i przewinęłam do najnowszego, ponownie bazuję:

git checkout devel0
git rebase master
git push -f origin devel0

Inni programiści wiedzą wtedy, że będą musieli przebudować swoje gałęzie deweloperskie na moje najnowsze:

git fetch <remote>
git checkout devel1
git rebase <remote>/devel0

Co skutkuje dużo czystszą historią:

o-----o                                 master
       \
         o-----o-----o                  devel0
                      \
                        o-----o-----o   devel1

Nie łącz zobowiązań w tę iz powrotem według własnego uznania. Nie tylko tworzy duplikaty zatwierdzeń i uniemożliwia śledzenie historii, ale znalezienie regresji z określonej zmiany staje się prawie niemożliwe (dlatego właśnie używasz kontroli wersji w pierwszej kolejności, prawda?). Problem, który masz, jest wynikiem zrobienia tego.

Wygląda też na to, że inni programiści mogą wprowadzać zmiany do twoich gałęzi deweloperskich. Czy możesz to potwierdzić?

Scalanie odbywa się tylko wtedy, gdy gałąź tematyczna jest gotowa do zaakceptowania master.

Na marginesie. Jeśli wielu programistów zatwierdza to samo repozytorium, wszyscy powinniście rozważyć nazwane gałęzie, aby rozróżnić gałęzie deweloperskie. Na przykład:

git branch 'my-name/devel-branch'

Zatem wszystkie gałęzie tematów deweloperów znajdują się we własnym zagnieżdżonym zestawie.


1
„Wygląda też na to, że inni programiści mogą wprowadzać zmiany do twoich gałęzi rozwojowych. Czy możesz to potwierdzić?” TAK, oni są ...
Matt,

Zwrócił pan też moją uwagę na inną kwestię. Praca między biurem a domem. Łączę się w obu miejscach i na koniec dnia wciskam, abym mógł wznowić od miejsca, w którym skończyłem. Następnie, kiedy nadejdzie czas na zmianę bazy, wszystkie te zatwierdzenia powodują zamieszanie. Muszę traktować moje oddziały jako jedną gałąź i rebase
Matt

@Matt Tak, te dwa problemy naprawdę spieprzą twój przepływ pracy. Po pierwsze, poinformowałbym innych programistów, że tylko właściciel może zobowiązać się do nazwanego rozgałęzienia (np. „Matt / devel”). IMHO, i tak żadne dwóch programistów nie powinno angażować się w tę samą gałąź. Po prostu tworzy zamieszanie. Z drugiej strony, ponowne bazowanie i pchanie siłowe powinny zapewnić aktualność obu lokalizacji.
Trevor Norris

Świetna odpowiedź. Mam dodatkowe pytanie, dlaczego używasz --forceflagi, kiedy to robisz git push -f origin devel0?
Aurelio

2
@Nobita Kiedy git pushnie można przewinąć do przodu (np. Historia sha się nie zgadza), musisz wymusić wypychanie, aby nadpisać poprzednią historię nową historią wygenerowaną z pliku git rebase.
Trevor Norris

52

Musisz wymusić push, ponieważ przesuwałeś zatwierdzenia dalej w dół wiersza, którego git oczekuje, że dodasz zatwierdzenia na końcu gałęzi. git push -f origin myNewFeaturerozwiąże twój problem.

Wskazówka: Powyższe to uzasadnione użycie siły. Nigdy, przenigdy nie przepisuj historii w publicznie dostępnym repozytorium, bo wiele osób cię nienawidzi.


1
Uważam, że jest to najbardziej optymalny sposób na utrzymanie przepływu pracy.
Syed Priom

2
Dzięki stary. Użyłem tego polecenia, aby wymusić na moim oddziale lokalnym opartym na rebase do tej samej gałęzi zdalnej.
wei

11
używanie git push --force-with-leasejest znacznie bezpieczniejsze niż używaniegit push --force

git push --force-with-lease origin HEAD- zakładając, że Twoja docelowa gałąź jest już
zameldowana

@LucaciSergiu co robi --force-with-lease?
kisanme

31

Najważniejszą rzeczą, o której należy pamiętać, jest to, co pull i rebase robią za kulisami.

Wyciąganie zasadniczo robi dwie rzeczy: pobieranie i scalanie. Gdy włączysz --rebase, zamiast scalania wykona rebase.

Ponowna baza jest prawie jak przechowywanie wszystkich lokalnych zmian od momentu rozgałęzienia, szybkie przekazywanie gałęzi do ostatniego zatwierdzenia celu i usuwanie zmian w kolejności na górze.

(To wyjaśnia, dlaczego możesz otrzymać wiele monitów o rozwiązanie konfliktu podczas wykonywania rebase w porównaniu z jednym rozwiązaniem konfliktu, które możesz uzyskać przy scalaniu. Masz możliwość rozwiązania konfliktu na KAŻDYM zatwierdzeniu, które jest zmieniane, aby w inny sposób zachować swoje zatwierdzenia. )

Nigdy nie chcesz wypychać zmian opartych na rebase do zdalnych gałęzi, ponieważ jest to przepisywanie historii. Z grubsza, nigdy nie jest zbyt mocny, ponieważ prawie zawsze są wyjątki. Sytuacja, w której musisz utrzymywać zdalną wersję lokalnego repozytorium, aby na przykład pracować w określonym środowisku.

Będzie to wymagało czasami wprowadzania zmian opartych na rebase za pomocą siły:

git push -f origin newfeature

W niektórych przypadkach administrator mógł usunąć możliwość wymuszenia, więc musisz usunąć i odtworzyć:

git push origin :newfeature
git push origin newfeature

W każdym przypadku musisz mieć absolutną pewność, że wiesz, co robisz, jeśli ktoś inny współpracuje z tobą w zdalnym oddziale. Może to oznaczać, że na początku pracujesz razem ze scaleniami i przebudowujesz je na łatwiejszy w zarządzaniu format zatwierdzania tuż przed przejściem do mastera i usunięciem gałęzi roboczej.

Pamiętaj, że prawie zawsze możesz wrócić do GC git, korzystając z:

git reflog

Jest to OGROMNA ochrona życia, ponieważ możesz zresetować z powrotem do bardziej stabilnego stanu, jeśli zgubisz się w całym zarządzaniu rebase / konfliktami.


Powyższa opcja usuwania i odtwarzania działała dobrze dla mnie. Żadne wymuszanie nie jest dozwolone w moim repozytorium!
Simon Holmes

2

Musisz wykonać wymuszony pchnięcie, tj git push -f origin myNewFeature

Aha, i lepiej upewnij się, że ludzie nie opierają niczego na twojej gałęzi deweloperskiej - zwykle nie powinieneś publikować gałęzi, w których w ogóle przepisujesz historię (lub raczej nie przepisujesz historii po opublikowaniu). Jednym ze sposobów byłoby użycie nazwy gałęzi, takiej jak, wip/myNewFeaturea następnie wspomnienie, że wipgałęzie będą od czasu do czasu przebudowywane na master.


używanie git push --force-with-leasejest znacznie bezpieczniejsze niż używaniegit push --force

@MrCholo Ludzie nie zaczną tego używać, dopóki git nie doda do tego krótkiej opcji, jak -fw przypadku normalnego wymuszonego pchnięcia :)
ThiefMaster

ha tak, użyłem go w zautomatyzowanym skrypcie, chociaż

2

Ogólna odpowiedź, która już została udzielona - do wykorzystania git push -f origin myNewFeatureprzy wprowadzaniu zmian opartych na rebase - jest dobrym punktem wyjścia. Piszę tę odpowiedź, aby zająć się edycją o tym, czy przerwie ona twój przepływ pracy.

Jeśli założymy, że masz zamiar używać git pull --rebase ...(lub pewne różnice na tym), a następnie przez siły-push do odległego oddziału, potem coś, co łamie workflow w przykładzie developer2 zlewa myNewFeaturesię hisNewFeature. Przebudowa własnej gałęzi funkcji ma sens, o ile nikt inny nie pracuje nad tą gałęzią, więc potrzebujesz reguł wyznaczających terytorium gałęzi.

Możesz to obejść, a) ustanawiając regułę, z której tylko się łączysz master, lub b) tworząc kolektywną developgałąź, na której opierasz swoją własną myNewFeaturegałąź i ustanawiając regułę, z której tylko łączysz się develop. masterbędzie wtedy zarezerwowana tylko dla kamieni milowych lub wydań (lub jakkolwiek chcesz to skonfigurować) i developbędzie tam, gdzie będziesz wypychać każdą funkcję, gdy będzie gotowa do zintegrowania z innymi gałęziami funkcji.

Uważam, że można to uznać za uproszczoną wersję przepływu pracy Gitflow.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.