2013-05-27 15 views
32

Pozwól mi opisać moją sytuację:Git: Ciągnięcie rebased oddział

Pan Blond i Pan Pomarańczowy pracują na oddział, który rozgałęzia się od głównego oddziału na popełnienia M1. Oddział A ma 2 zatwierdzenia: A1 i A2.

M1 
    \ 
    \ 
    A1 - A2 

Tymczasem Pan Pomarańczowy zaangażowana i pchnął 2 kolejne rewizje na gałęzi głównej, M2 i M3.

M1 - M2 - M3 
    \ 
    \ 
    A1 - A2 

Pan Blond ciągnie z pilota, a po chwili postanawia rebase na gałęzi master:

M1 - M2 - M3 
    \   \ 
    \   \ 
    A1 - A2 A1` - A2` 

Teraz A1` i A2` stanowią rebased commity że istnieje lokalnie na pana blondyna, a A1 i A2 istnieją zdalnie. Mr Blond przesuwa swoje zatwierdzenia, używając -f, aby wymusić swoje zmiany i historię "przepisywania". Teraz zdalne repozytorium wygląda następująco:

M1 - M2 - M3 
      \ 
       \ 
       A1` - A2` 

Ale Pan Orange również pracował w oddziale A. Jego lokalnego repozytorium nadal wygląda następująco:

M1 - M2 - M3 
    \ 
    \ 
    A1 - A2 

Co Pan Pomarańczowy trzeba zrobić, aby być zsynchronizowane z gałęzi w zdalnym repozytorium?

Normalne pociągnięcie nie działa. Czy pull -f wymusi lokalne zmiany na zdalnym? Wiem, że usunięcie lokalnej wersji A i ponowne jej przesłanie z odległego repozytorium wystarczy, ale wydaje się, że nie jest to dobry sposób na osiągnięcie tego.

Odpowiedz

21

Moja rekomendacja (lub, "co bym zrobił, gdybym był Mr Orange"), zaczyna się od git fetch. Teraz będę miał to w repozytorium, czyli to, co Mr Blond miał po swoim rebase i tuż przed uruchomieniem "git push-f".

M1 - M2 - M3 
    \   \ 
    \   \ 
    A1 - A2 A1' - A2' 

Jedną istotną różnicą jest to, będę mieć moją lokalną wytwórnię A wskazując rev a2, a pilot etykieta remotes/origin/A wskazując na A2' (Pan Blond miał to na odwrót, lokalny label A wskazując A2 'i remotes/origin/A wskazujące na A2).

Jeśli pracuję w moim egzemplarzu oddziału o nazwie „A” Muszę to zamiast:

M1 ---- M2 ---- M3 
    \    \ 
    \    \ 
    A1 - A2 - A3 A1' - A2' 

(z moim lokalnym etykieta wskazując A3 zamiast A2 lub A4 lub A5 itp., w zależności od tego, ile zmian zastosowałem.) Teraz wszystko, co muszę zrobić, to zmienić moje A3 (i A4 w razie potrzeby itd.) Na A2 '. Jednym z oczywistych bezpośredni sposób:

$ git branch -a 
    master 
* A 
    remotes/origin/master 
    remotes/origin/A 
$ git branch new_A remotes/origin/A 
$ git rebase -i new_A 

a następnie spadek obr A1 i A2 w całości, gdyż te są modyfikowane w new_A jako A1' i A2' . Lub:

$ git checkout -b new_A remotes/origin/A 
$ git format-patch -k --stdout A3..A | git am -3 -k 

(metoda git am -3 -k jest opisana w git-format-patch stronie podręcznika).

te wymagają zastanawianie się, co mam, że pan nie Blond przedtem czynił jego rebase, czyli identyfikacji A1, A2, A3 itd

Jeżeli drugie podejście jest skuteczne I skończyć z:

M1 ---- M2 ---- M3 
    \    \ 
    \    \ 
    A1 - A2 - A3 A1' - A2' - A3' 

gdzie nazywam oddział new_A punkty do A3' (mój istniejący A oddział nadal wskazuje na starą A3). Jeśli używam pierwszego podejścia i to się uda, kończę na tym samym, po prostu moja obecna nazwa oddziału A będzie teraz wskazywała na A3 '(i nie mam nazwy dla starego oddziału z A1-A2-A3, nawet chociaż wciąż jest w moim repozycie, znalezienie go wymaga przechodzenia przez reflogi lub podobne).

(Jeśli moje potrzeby A3 modyfikacji stać A3' , zarówno interaktywne rebase i «git am» metoda będzie wymagać pracy przeze mnie, oczywiście.)

Oczywiście jest to również możliwe, aby po prostu git merge (jak w odpowiedzi Gary Fixler), ale stworzy scalającej („M” bez numeru, poniżej) i utrzymać obroty A1 i A2 widoczne, dając:

M1 ---- M2 ---- M3 
    \    \ 
    \    \ 
    A1 - A2 - A3 A1' - A2' -- M 
       \_______________/ 

Jeśli chcesz zachować oryginalny A1 i A2, to jest dobra rzecz; jeśli chcesz się ich pozbyć, to źle. A więc "co robić" zależy od "tego, co chcesz osiągnąć".

Edytuj, aby dodać: bardziej podoba mi się metoda zmiany formatu, ponieważ pozostawia ona moją starą nazwę oddziału, podczas gdy ja upewniam się, że wszystko jest w porządku. Zakładając, że to wszystko działa i jest dobry, oto ostatnie kilka kroków:

$ git branch -m A old_A 
$ git branch -m new_A A 

a następnie, jeśli old_A może być opuszczony w całości:

$ git branch -D old_A 

lub, równoważnie, zacznij oddział usuwać następnie zmień nazwę new_A do A.

(Edit: patrz również git rebase --onto dokumentację, za cel przebazowania A3, etc., na oddziale new_A.)

30

Jeśli Pan Pomarańczowy nie przeszkadza tracąc swoje zmiany, może on pobrać z serwera, a następnie git checkout A2 dostać się na swoim lokalnym A2 oddziału, następnie (zakładając pilota jest nazwany „pochodzenie”) git reset --hard origin/A2 zresetować jego A2 do gdzie znajduje się zdalny numer A2.

Jeśli chodzi o utratę zmian, może scalić zmiany serwera, aby je rozwiązać (ze swojego własnego oddziału A2, i zakładając, że pilot nazywa się "origin") z git merge origin/A2. Spowoduje to utworzenie nowego zatwierdzenia, które będzie znajdować się na gałęziach zarówno jego, jak i odległych, A2 ze zmianami z obu scalonych razem. Następnie można go odepchnąć do pilota.

+1

Uwaga: nie ma białych spacji między '-' a 'hard' - zajęło mi to trochę czasu, ponieważ odpowiedź została umieszczona na moim ekranie dokładnie pomiędzy tymi dwoma :) – qbolec