Zauważyłem, że dwa bloki następujących poleceń git mają różne zachowania i nie rozumiem dlaczego.
Mam A
i B
gałąź, która różni się od jednejcommit
---COMMIT--- (A)
\
--- (B)
Chcę zmienić B
gałąź na najnowszą A
(i mieć zatwierdzenie na B
gałęzi)
---COMMIT--- (A)
\
--- (B)
Nie ma problemu, jeśli to zrobię:
checkout B
rebase A
Ale jeśli to zrobię:
checkout B
rebase --onto B A
W ogóle nie działa, nic się nie dzieje. Nie rozumiem, dlaczego te dwa zachowania są różne.
Klient git Phpstorm używa drugiej składni, więc wydaje mi się, że jest całkowicie zepsuty, dlatego proszę o ten problem ze składnią.
git
git-rebase
Xmanoux
źródło
źródło
Odpowiedzi:
tl; dr
Poprawna składnia do rebase
B
na górzeA
używającgit rebase --onto
w Twoim przypadku jest:lub rebase
B
na początkuA
od zatwierdzenia, które jest rodzicem, do któregoB
odwołuje sięB^
lubB~1
.Jeśli interesuje Cię różnica między
git rebase <branch>
igit rebase --onto <branch>
czytaj dalej.Szybki: git rebase
git rebase <branch>
ma zamiar ponownie bazować gałąź, którą aktualnie sprawdzałeś, do której odwołujeHEAD
się najnowszy zatwierdzenie, które jest dostępne z,<branch>
ale nie zHEAD
.Jest to najczęstszy przypadek zmiany bazy i prawdopodobnie ten, który wymaga mniej planowania z góry.
W tym przykładzie
F
iG
są zatwierdzeniami, które są dostępne z,branch
ale nie zHEAD
. Powiedzeniegit rebase branch
weźmieD
, to jest pierwszy zatwierdzenie po punkcie rozgałęzienia, i ponownie go oprze (tj. Zmieni jego rodzica ) na najnowszym zatwierdzeniu osiągalnym od,branch
ale nie odHEAD
, to znaczyG
.Precyzja: git rebase --onto z 2 argumentami
git rebase --onto
pozwala na zmianę bazy zaczynając od określonego zatwierdzenia . Daje ci dokładną kontrolę nad tym, co jest zmieniane i gdzie. Dotyczy to scenariuszy, w których musisz być precyzyjny.Na przykład wyobraźmy sobie, że musimy
HEAD
dokładnie zmienić bazę ,F
zaczynając odE
. Jesteśmy zainteresowani tylko wprowadzeniemF
do naszej działającej gałęzi, a jednocześnie nie chcemy zachować,D
ponieważ zawiera pewne niekompatybilne zmiany.W tym przypadku powiedzielibyśmy
git rebase --onto F D
. To znaczy:Innymi słowy, zmień rodzica z
E
zD
naF
. Składniagit rebase --onto
jest zatemgit rebase --onto <newparent> <oldparent>
.Innym scenariuszem, w którym jest to przydatne, jest sytuacja, gdy chcesz szybko usunąć niektóre zatwierdzenia z bieżącej gałęzi bez konieczności wykonywania interaktywnej rebase :
W tym przykładzie, aby usunąć
C
izE
sekwencji, możesz powiedziećgit rebase --onto B E
, lub zmienić bazęHEAD
na miejscu, wB
którym był stary rodzicE
.The Surgeon: git rebase --onto z 3 argumentami
git rebase --onto
jeśli chodzi o precyzję, może pójść o krok dalej. W rzeczywistości pozwala na przeniesienie dowolnego zakresu zatwierdzeń na inny.Oto przykład:
W tym przypadku chcemy zmienić dokładny zakres
E---H
na górzeF
, ignorując miejsce, na któreHEAD
aktualnie wskazuje. Możemy to zrobić, mówiącgit rebase --onto F D H
, co oznacza:Następnie składnia
git rebase --onto
z zakresem zatwierdzeń staje sięgit rebase --onto <newparent> <oldparent> <until>
. Sztuczka polega na tym, że należy pamiętać, że zatwierdzenie, do którego odwołuje się,<until>
jest zawarte w zakresie i stanie się nowymHEAD
po zakończeniu rebase.źródło
<oldparent>
nazwa nie działa, jeśli dwie części zakresu znajdują się w różnych gałęziach. Generalnie jest to: „Uwzględnij wszystkie zatwierdzenie, które jest osiągalne z,<until>
ale wyklucz każde zatwierdzenie, które jest osiągalne z<oldparent>
”.git rebase --onto <newparent> <oldparent>
jest najlepszym wyjaśnieniem zachowania, jakie widziałem!--onto
opcją, ale to sprawiło, że stało się jasne! Nawet nie rozumiem, jak nie mogłem tego wcześniej zrozumieć: D Dzięki za doskonały "tutorial" :-)To wszystko, co musisz wiedzieć, aby zrozumieć
--onto
:Przełączasz rodzica na zatwierdzenie, ale nie podajesz sha tego zatwierdzenia, tylko sha jego obecnego (starego) rodzica.
źródło
Krótko mówiąc, biorąc pod uwagę:
Który jest taki sam jak (ponieważ
--onto
przyjmuje jeden argument):Środki rebase zobowiązuje się w zakresie (D, H] na górze F. Zawiadomienie zakres jest lewa wykluczają. Jest to ekskluzywny, ponieważ łatwiej jest określić 1-ci popełnić wpisując np
branch
pozwolićgit
znaleźć 1st odbiegał popełnić odbranch
znaczyD
co prowadzi doH
.Sprawa OP
Można zmienić na pojedyncze polecenie:
To, co wygląda na błąd, to umieszczenie,
B
które oznacza „przenieś niektóre zatwierdzenia, które prowadzą do gałęziB
na wierzchB
”. Pytanie brzmi, czym są „niektóre zatwierdzenia”. Jeśli dodasz-i
flagę, zobaczysz, że jest to pojedyncze zatwierdzenie, na które wskazujeHEAD
. Zatwierdzenie jest pomijane, ponieważ zostało już zastosowane do--onto
celuB
i nic się nie dzieje.To polecenie jest bezsensowne w każdym przypadku, gdy nazwa gałęzi jest powtarzana w ten sposób. Dzieje się tak, ponieważ zakres zatwierdzeń będzie obejmował niektóre zatwierdzenia, które są już w tej gałęzi, a podczas rebase wszystkie zostaną pominięte.
Dalsze wyjaśnienia i zastosowanie
git rebase <upstream> <branch> --onto <newbase>
.git rebase
domyślne.Rozwija się do:
Automatyczne kasy po rebase.
W przypadku standardowego użycia, na przykład:
Nie zauważysz, że po rebase
git
przechodzibranch
do ostatniego zmiany bazy danych i robigit checkout branch
(zobaczgit reflog
historię). Co jest interesujące, gdy drugim argumentem jest wartość skrótu commita, zamiast tego nazwa gałęzi rebase nadal działa, ale nie ma gałęzi do przeniesienia, więc kończysz w "odłączonym HEAD" zamiast wyrejestrowywania do przeniesionej gałęzi.Pomiń pierwotne rozbieżne zatwierdzenia.
master
W--onto
pochodzi z 1git rebase
argument.Tak praktyczne, że może to być dowolne inne zatwierdzenie lub gałąź. W ten sposób możesz ograniczyć liczbę zatwierdzeń rebase, biorąc najnowsze i pozostawiając pierwotne rozbieżne zatwierdzenia.
Przebuduje pojedyncze zatwierdzenie wskazywane przez
HEAD
tomaster
i zakończy się w „odłączonym HEAD”.Unikaj jawnych kasów.
Wartość domyślna
HEAD
lubcurrent_branch
argument jest pobierana kontekstowo z miejsca, w którym się znajdujesz. Dlatego większość ludzi zameldowuje się w oddziale, w którym chce zmienić bazę. Ale kiedy drugi argument rebase zostanie podany jawnie, nie musisz wyewidencjonowywać go przed rebase, aby przekazać go w sposób niejawny.Oznacza to, że możesz zmienić bazę zatwierdzeń i rozgałęzień z dowolnego miejsca. A więc razem z automatycznym kasowaniem po ponownymbase. nie musisz osobno płacić oddziału z rebase'em przed lub po rebase.
źródło
Mówiąc najprościej,
git rebase --onto
wybiera zakres zatwierdzeń i opiera je na zatwierdzeniu podanym jako parametr.Przeczytaj strony podręcznika man
git rebase
, wyszukaj „na”. Przykłady są bardzo dobre:W tym przypadku mówisz gitowi, aby zmienił bazę zatwierdzeń od
topicA
dotopicB
na górzemaster
.źródło
Aby lepiej zrozumieć różnicę między
git rebase
igit rebase --onto
dobrze jest wiedzieć, jakie są możliwe zachowania obu poleceń.git rebase
pozwalają nam przenieść nasze zatwierdzenia na wybraną gałąź. Jak tutaj:a wynik to:
git rebase --onto
jest bardziej precyzyjny. Pozwala nam wybrać konkretne zatwierdzenie, od którego chcemy zacząć, a także gdzie chcemy zakończyć. Jak tutaj:a wynik to:
Aby uzyskać więcej informacji, polecam zapoznać się z moim własnym artykułem na temat przeglądu git rebase --onto
źródło
git rebase --onto F D
jako ustawione dziecko rodzica D jako F , prawda?Dla
onto
potrzebne są dwa dodatkowe oddziały. Za pomocą tego polecenia możesz zastosować zmiany zbranchB
bazującebranchA
na innej gałęzi, npmaster
. W poniższym przykładziebranchB
jest oparty nabranchA
i chcesz zastosować zmianybranchB
onmaster
bez stosowania zmianbranchA
.za pomocą poleceń:
otrzymasz następującą hierarchię zatwierdzeń.
źródło
rebase --onto branchA branchB
oznaczałoby to postawienie całej gałęzi głównej na czele gałęzi A?checkout branchB: rebase --onto master branchA
?Jest jeszcze jeden przypadek, w którym
git rebase --onto
jest trudny do zrozumienia: kiedy ponownie bazujesz na zatwierdzeniu wynikającym z selektora symetrycznej różnicy (trzy kropki '...
')Git 2.24 (Q4 2019) radzi sobie lepiej z tym przypadkiem:
Zobacz commit 414d924 , commit 4effc5b , commit c0efb4c , commit 2b318aa (27 sierpnia 2019) i commit 793ac7e , commit 359eceb (25 sierpnia 2019) autorstwa Denton Liu (
Denton-L
) .Z pomocą: Eric Sunshine (
sunshineco
) , Junio C Hamano (gitster
) , Ævar Arnfjörð Bjarmason (avar
) i Johannes Schindelin (dscho
) .Zobacz commit 6330209 , commit c9efc21 (27 sierpnia 2019) i commit 4336d36 (25 sierpnia 2019) autorstwa Ævar Arnfjörð Bjarmason (
avar
).Z pomocą: Eric Sunshine (
sunshineco
) , Junio C Hamano (gitster
) , Ævar Arnfjörð Bjarmason (avar
) i Johannes Schindelin (dscho
) .(Scalone przez Junio C Hamano -
gitster
- w zatwierdzeniu 640f9cd , 30 września 2019)W tym miejscu przeczytaj " Jakie są różnice między podwójną kropką
..
" a potrójną kropką "...
" w zakresach zatwierdzania Git diff? "Tutaj: „
master...
” odnosi się domaster...HEAD
, czyliB
: HEAD to strona HEAD (aktualnie wyrejestrowana): zmieniasz bazęB
.Co podważasz? Dowolne zatwierdzenie, które nie jest w master i jest dostępne z
side
gałęzi: jest tylko jeden zatwierdzenie pasujące do tego opisu:D
... który już jest na wierzchuB
!Ponownie, przed Git 2.24, takie
rebase --onto
rozwiązanieD
zawsze powodowałoby ponowne bazowanie, bez względu na wszystko.To jest podobne do
rebase --onto B A
PO, który nic nie zrobił.a polecenie upadło
A
rebase --onto C F topic
oznacza każde zatwierdzenie poF
, osiągalne przeztopic
HEAD: to jestG
tylko, a nieF
siebie.W tym przypadku
F
przewijanie do przodu obejmowałoby gałąź ponownie bazującą, co jest błędne.źródło