Git rozdzielił się po rebase

112

Przebudowałem lokalnie gałąź, która została już przeniesiona.

Git informuje, że mój oddział i pilot rozeszły się i że:

"i mają odpowiednio 109 i 73 różne zatwierdzenia"

Czy wypchnięcie mojej gałęzi rozwiąże ten problem - tj. Czy można się tego spodziewać po rebase?

Marty Wallace
źródło
Mam ten sam problem. Czy można powiedzieć, że „właściwą drogą” jest przebudowa lokalnego oddziału i dopiero wtedy forsowanie?
Mher Didaryan,

Odpowiedzi:

154

Kiedy przebudowujesz gałąź, musisz przepisać zatwierdzenia dla każdego zatwierdzenia, które znajduje się powyżej zatwierdzeń w gałęzi, na której ponownie bazujesz. Dzieje się tak, ponieważ jedną z właściwości zatwierdzenia jest jego rodzic (lub rodzice). Kiedy dokonujesz rebase, zmieniasz rodzica najstarszego lokalnego zatwierdzenia w twojej gałęzi - a tym samym zmieniasz skróty zatwierdzeń wszystkich lokalnych zatwierdzeń, ponieważ ta zmiana przenosi się przez zatwierdzenia przejściowo.

Ponieważ już wypchnąłeś gałąź, powinieneś był połączyć się z gałęzią źródłową, zamiast opierać się na niej. Możliwe jest "wymuszenie wypchnięcia" twojej nowej gałęzi (używając -fflagi), ale normalny push nie zadziała, ponieważ integralność historii gałęzi zostanie zakłócona. Jeśli współpracujesz z innymi osobami w tej gałęzi, forsowanie siły jest złym pomysłem, ponieważ spowoduje, że inni współpracownicy będą bardzo zdezorientowani, gdy ich historia nagle się nie zgadza.

TL; DR - Jeśli nie współpracujesz, wypchnij gałąź za pomocą push -f. Jeśli tak, zresetuj gałąź do poprzedniego stanu i zamiast tego scal ją w gałęzi źródłowej.

Jason LeBrun
źródło
1
„Skoro już wypchnąłeś gałąź, powinieneś był włączyć ją do gałęzi źródłowej” - dlaczego tak jest?
hammett
1
Pierwsze zdanie @HamiltonVerissimo Jasona: „Kiedy przebudowujesz gałąź, musisz przepisać zatwierdzenia dla każdego zatwierdzenia, które znajduje się powyżej zatwierdzeń w gałęzi, na której ponownie bazujesz.” Mimo że zmiany uchwycone w "powyższych" zatwierdzeniach mają tę samą logiczną zawartość, są one stosowane do innej bazy i dlatego są różnymi zatwierdzeniami z różnymi skrótami. Jeśli inni programiści pracują z gałęzi pre-rebased, wykonanie polecenia git push -f mogłoby bardzo zakłócić ich przepływ pracy. Tak więc, skoro ta gałąź została zepchnięta do publicznego źródła, powinien był się połączyć.
awolf
4
możesz również użyć push --force-with-lease, jeśli nie jesteś pewien, czy ktoś inny już coś zrobił.
Konsola
1
@ jason-lebrun Czy nie jest wadą scalania zewnętrznych zmian, że możesz nadpisać własną pracę bez ostrzeżenia? Czy konflikty scalania są wykrywane w taki sam sposób, jak podczas ponownego bazowania? Na przykład, jeśli usunę sekcję z pliku w mojej gałęzi, ponieważ nie jest już potrzebna, ale ktoś inny wprowadził trywialną zmianę w tej samej sekcji w górnej części, na przykład usunięcie jakiejś białej spacji lub jakiejś globalnej akcji znajdowania / zamieniania, nie scalenie tego na górze mojej gałęzi zastąpić moje usunięcie ich trywialnie zmienioną wersją?
Chris Bloom,
1
Czy połączenie drugiej gałęzi z Twoją nie jest złym pomysłem? Np. Scalanie mastera w gałąź funkcji - czy to nie stworzy nowego zatwierdzenia? Czy nie spowoduje to dodatkowego zatwierdzenia po rozgałęzieniu tej funkcji, jeśli później zostanie scalone z wzorcem?
Ross
55

Wszystkie twoje zatwierdzenia zmieniły identyfikatory, więc dywersja nie jest tak naprawdę rozbieżna.

Aby rozwiązać problem , musisz nadpisać zdalną gałąź:

git push -f origin experiment

http://git-scm.com/book/ch3-6.html

Wyjaśnienie:

Zobacz, jak na tym obrazku C3 nie jest wstawiane jako C3 po rebase, ale jako C3 '. Dzieje się tak, ponieważ nie jest to dokładnie C3, ale ma wszystkie zmiany w kodzie.

Rebase

Na tym drugim obrazie widać, co widzi rebase, gdy w grę wchodzi pilot, i dlaczego występuje przekierowanie.

odejdź i popchnij

W każdym razie, po wykonaniu wymuszonego pchnięcia, powie ci, że wykonał (wymuszoną aktualizację), w tym momencie powinno być dobrze.

Sprawdź link u góry i wyszukaj „git push --force”. Zobaczysz bardziej szczegółowe wyjaśnienie.

mimoralea
źródło
3
Tak. Myślę, że to rozwiązuje problem. Jednak pchnięcie siły może nie działać, gdy pracujesz w zespole, gdy naciśnięcie może nadpisać ostatnią pracę wymuszoną przez innych. Czy mam rację?
Hari Krishna Ganji
Może nie przynieść pożądanych efektów. Upewnij się, że scaliłeś swoje zmiany „szybko do przodu” przed wykonaniem rebase.
mimoralea
1

Udało mi się odejść od rebase, wykonując następujące czynności:

git checkout mybranch
git pull
git push origin mybranch

Pociągnięcie rozwiązało rozbieżność.

PRZED pociągnięciem

Your branch and 'origin/mybranch' have diverged,
and have 2 and 1 different commit(s) each, respectively.

Wyjście PULL

Scalanie rekurencyjne. mypath / myfile.py | 12 +++++++++++ - 1 plik zmieniony, 11 wstawień (+), 1 usunięcia (-)

PO pociągnięciu

Twoja gałąź wyprzedza „origin / mybranch” o 3 zatwierdzenia.

PO PUSH

mybranch wyprzedza gałąź o 3, ale nadal ma otwartą wiadomość pull request dodaną do historii zatwierdzeń Połącz gałąź mybranch of remote do mybranch

Zakładam, że jest to prawdopodobnie to, co robi pchnięcie siły i nie zweryfikowałem.

Jak powiedzieli inni, unikaj ponownego bazowania, jeśli masz już otwarte żądanie ściągnięcia. Podaję ten przykład jako coś, co zadziałało dla mnie.

zerocog
źródło
1

Można to naprawić bez pchania siły, przenosząc gałąź docelową do bieżącej gałęzi lokalnej, przełączając się na gałąź docelową, a następnie przekształcając gałąź lokalną w docelową. To się nie różni, ponieważ zmiany, których może brakować, są dodawane i nie trzeba ich już tworzyć. Przykład łatwiejszego wyjaśnienia:

  1. główna gałąź jest rozwijana
  2. Kupujesz nową funkcję oddziału / doing_stuff
  3. Członek zespołu popycha nowe zobowiązanie do rozwoju

Jeśli NIE zaktualizowałeś swojej gałęzi deweloperskiej, wtedy "git checkout develop" && "git rebase feature / doing_stuff" będzie działać poprawnie, ponieważ nie dodano żadnych zatwierdzeń od czasu twojego zamówienia. Jeśli jednak sprawdziłeś program i usunąłeś nowy commit, zobaczysz tę rozbieżność, jeśli spróbujesz zmienić bazę z powodu zobaczenia nowego zatwierdzenia. Łatwym rozwiązaniem bez naciskania na siłę (zwykle nie jest to dobry pomysł w środowisku zespołowym) jest:

  1. git checkout feature / doing_stuff
  2. git rebase rozwijać
  3. git checkout rozwijać
  4. git rebase feature / doing_stuff

Rebase z kroku 2 przenosi brakujące zatwierdzenie do feature / doing_stuff, więc gdy pojawia się krok 4, jest aktualny i nie ma potrzeby tworzenia nowego zatwierdzenia dla zmiany.

Jest to rozwiązanie, o którym wiem, że działa, ponieważ właśnie na to wpadłem i wykonałem powyższe kroki, aby pomyślnie uruchomić programowanie bez użycia siły. Pracuję w ponad 50-osobowym zespole programistów, więc nie wolno wymuszać niczego innego niż moje własne gałęzie testowe, więc musiałem znaleźć rozwiązanie.

Chris
źródło