Zmień bazę oddziału

157

Mam takie drzewo:

(commit 1) - master
                \-- (commit 2) - (commit 3) - demo
                                                \-- (commit 4) - (commit 5) - PRO

i muszę przenieść gałąź PRO do mastera

(commit 1) - master
                |-- (commit 2) - (commit 3) - demo
                \-- (commit 4) - (commit 5) - PRO

Próbowałem git rebase masterz oddziału PRO, ale nic się nie dzieje.

Dla wyjaśnienia : pracowałem w master, a potem musiałem zrobić demo produktu ( git checkout -b demoi kilka commits). Potem przez pomyłkę tworzę kolejną gałąź z demo ( git checkout -b PROi niektórych zatwierdzeń) i teraz muszę przenieść gałąź PRO do mastera i pozostawić demo nienaruszone. Na koniec zarówno wersja demo, jak i wersja PRO zostaną zawieszone na master.

Ivan
źródło
możliwy duplikat punktu odgałęzienia Change
Wladimir Palant

Odpowiedzi:

319

Użyj --ontodo tego:

git rebase --onto newBase oldBase feature/branch

Biorąc pod uwagę Twój przypadek:

git checkout PRO # Just to be clear which branch to be on.
git rebase --onto master demo PRO

Zasadniczo pobierasz wszystkie zatwierdzenia od po demodo PROi przekształcasz je w masterzatwierdzenie.

loganfsmyth
źródło
Czy to też jest droga, jeśli sytuacja jest odwrotna? == Kasy -b od mastera z drugiej gałęzi, ale chciałem to zrobić z pierwszej. Tak zrobiłem, git rebase --onto first-branch second-branch second-branchale nie rozumiem składni
Fla
1
@Fla w takim przypadku byłobygit rebase --onto first-branch master second-branch
nVitius
11
Czytałem ten podręcznik na temat --onto, i jak pisali mi pomógłgit rebase --onto newBase oldBase feature/branch
Gabe
@PhilipRego To jest nieprawidłowe. origin/newBaseto nazwa gałęzi, tak jak newBasew moim przykładzie. Zależałoby to tylko od tego, czy ponownie bazujesz na gałęzi, która istnieje w twoim lokalnym repozytorium ( newBase), czy też takiej, która istnieje w zdalnym ( origin/newBase).
loganfsmyth
@PhilipRego To nie są niezależne rzeczy. newBaseto nazwa oddziału lokalnego, a origin/newBaseto nazwa oddziału zdalnego. Który z nich chcesz, zależy od tego, na czym się opierasz. Nie chodzi o to, że się pracuje, a nie tak, chodzi o to, że bazują na innych rzeczach. Oryginalne pytanie nigdy nie wspomina o pilotach, więc użycie pilotów w moim przykładzie nie pasowałoby do zadanego pytania.
loganfsmyth
25

Sprawdź do PROgałęzi, skopiuj najstarsze ( zatwierdzenie4 ) i najnowsze ( zatwierdzenie5 ) skróty zatwierdzeń tej gałęzi i wklej gdzie indziej:

$ git checkout PRO
$ git log            # see the commit history
# copy the oldest & latest commit-hash 

Usuń PROgałąź (zachowaj kopię zapasową tylko dla bezpieczeństwa). Utwórz i zapłać do nowego PROoddziału z master:

$ git branch PRO.bac    # create a new branch PRO.bac = PRO as backup

$ git checkout master
$ git branch -D PRO     # delete the local PRO branch
$ git checkout -b PRO   # create and checkout to a new 'PRO' branch from 'master'

Weź (najlepszy wybór ) zakres zatwierdzeń poprzedniej PROgałęzi do nowej PROgałęzi:

$ git cherry-pick commit4^..commit5   # cherry-pick range of commits
# note the '^' after commit4

Teraz, jeśli wszystko jest w porządku, wymuś (-f) wypchnij do remote PROgałęzi i usuń PRO.bacgałąź lokalną :

$ git log                  # check the commit history

$ git push -f origin HEAD  # replace the remote PRO by local PRO branch history
# git branch -D PRO.bac    # delete local PRO.bac branch
Sajib Khan
źródło
23

Postaram się być tak ogólnikowy, jak tylko mogę. Najpierw upewnij się, że jesteś na wybranej gałęzi:

git checkout current-branch

Następnie użyj następującego polecenia (gdzie new-base-branchjest gałąź, która ma być twoją nową bazą, a current-base-branchjest to gałąź, która jest twoją aktualną bazą).

git rebase --onto new-base-branch current-base-branch

Jeśli nie masz konfliktów, to świetnie - gotowe. Jeśli tak (w większości przypadków), czytaj dalej.

Mogą pojawić się konflikty, które trzeba będzie rozwiązać ręcznie. Git teraz próbuje zrobić „3-drożny seryjnej” między telefonem current-branch, current-base-brancha new-base-branch. Z grubsza tak będzie działać wewnętrznie git:

  1. Git najpierw przebuduje bazę current-base-branchna new-base-branch. Mogą wystąpić konflikty; które będziesz musiał rozwiązać ręcznie. Po zakończeniu zwykle robisz git add .i git rebase --continue. W tym celu utworzy nowe tymczasowe zatwierdzenie temp-commit-hash.

  2. Po tym Git będzie teraz ponownie bazował current-branchna temp-commit-hash. Mogą wystąpić dalsze konflikty i znowu będziesz musiał rozwiązać je ręcznie. Po zakończeniu kontynuuj ponownie z git add .i git rebase --continue, po czym z powodzeniem ponownie bazujesz current-branchna new-base-branch.


Uwaga: jeśli zaczniesz się bałaganić, możesz to zrobić w git rebase --abortdowolnym momencie podczas procesu rebase i wrócić do punktu wyjścia.

ARKA
źródło
Wysłane rebasepolecenie po prostu daje mi komunikat „fatal: invalid upstream 'current-base-branch'”. Ponadto, dlaczego w ogóle jest konieczne, aby powiedzieć GIT, jaka jest bieżąca gałąź nadrzędna tej gałęzi - czy nie powinna już tego wiedzieć?
Matt Arnold
2

Przyjąłem nieco inne podejście, używając resetowania i skrytek, które pozwalają uniknąć usuwania i ponownego tworzenia gałęzi, a także eliminują potrzebę zmiany gałęzi:

$ git checkout PRO
$ git reset commit4 # This will set PROs HEAD to be at commit 4, and leave the modified commit 5 files in ur working index
$ git stash save -m "Commit message"
$ git reset commit 3
$ git stash save -m "Commit message"
$ git reset master --hard
$ git stash pop
$ git stash pop
$ git push --force # force if its already been push remotely

Resetując gałąź na podstawie zatwierdzenia przez zatwierdzenie, w zasadzie po prostu przewijasz historię rozgałęzień do zatwierdzenia na raz.

madjase
źródło
Czy należy usunąć spację między „zatwierdzeniem” a „3” w czwartej linii?
Alexis Wilke