Zrozumienie i zapamiętanie parametrów git rebase

12

Jak dotąd najbardziej myląca część git opiera się na innej gałęzi. W szczególności mylące są argumenty wiersza poleceń.

Za każdym razem, gdy chcę osadzić mały fragment jednej gałęzi na wierzchołku innego, muszę przejrzeć dokumentację git rebase i zajmuje mi to około 5-10 minut, aby zrozumieć, jaki powinien być każdy z 3 głównych argumentów.

git rebase <upstream> <branch> --onto <newbase>

Jaka jest dobra ogólna zasada, która pomaga mi zapamiętać, na co należy ustawić każdy z tych 3 parametrów, biorąc pod uwagę jakąkolwiek bazę w innej gałęzi?

Pamiętaj, że wielokrotnie przeglądałem dokumentację git-rebase, i wciąż, i wciąż, i znowu (i znowu), ale zawsze trudno to zrozumieć (jak nudna biała księga naukowa czy coś takiego). W tym momencie czuję, że muszę zaangażować innych ludzi, aby pomogli mi to zrozumieć.

Moim celem jest to, że nigdy nie powinienem sprawdzać dokumentacji tych podstawowych parametrów. Do tej pory nie byłem w stanie ich zapamiętać i już zrobiłem mnóstwo rebase'ów. Jest więc trochę niezwykłe, że do tej pory byłem w stanie zapamiętać każde inne polecenie i jego parametry, ale nie bazowałem na nim --onto.

void.pointer
źródło
Możesz albo zdefiniować niektóre aliasy git dla typowych przypadków użycia, albo podrzucić skrypt kreatora, który przypomni ci, co oznacza każdy z parametrów przed wykonaniem polecenia.
Rory Hunter
4
Ach, te oszałamiające, czysta elegancja opcji poleceń git. Tak intuicyjny w użyciu. Zawsze prawdziwa przyjemność.
JensG

Odpowiedzi:

10

Pomińmy --ontona chwilę. upstreami branchsą dość proste, a właściwie trochę naśladują checkouti branch- drugi argument jest opcjonalny:

git branch <newbranch>
git branch <newbranch> <base>
git checkout -b <newbranch>
git checkout -b <newbranch> <base>
git rebase <upstream>
git rebase <upstream> <branch>

(Bok, nazwy tych argumentów rebase„upstream” i „branży” nie są bardzo opisywać zawartość IMO ja zwykle myśleć o nich jak peachoftree,. <start>I <end>, co jest, jak będę je za pomocą: git rebase <start> <end>)

Po pominięciu drugiej gałęzi wynik jest prawie taki sam, jak najpierw sprawdzenie tej gałęzi, a następnie wykonanie jej tak, jakby nie określono tej gałęzi. Wyjątkiem jest to, branchże nie zmienia twojej aktualnej gałęzi:

git checkout <base> && git branch <newbranch> && git checkout <previous_branch>
git checkout <base> && git checkout -b <newbranch>
git checkout <end>  && git rebase <start>

Jeśli chodzi o zrozumienie, co rebaserobi po wywołaniu, zacząłem od myślenia o tym jako o specjalnym typie scalania. To nie jest tak naprawdę, ale pomogło, gdy po raz pierwszy zaczął rozumieć bazę. Aby pożyczyć przykład peachoftree:

A--B--F--G master
    \
     C--D--E feature

A git merge masterwyniki w tym:

A--B--F-----G master
    \        \
     C--D--E--H feature

Podczas gdy git rebase master(podczas gdy na gałęzi feature!) Powoduje to:

A--B--F--G master
          \
           C'--D'--E' feature

W obu przypadkach featurezawiera teraz kod z obu masteri feature. Jeśli nie jesteś włączony feature, możesz użyć drugiego argumentu, aby przejść do niego jako skrótu: git rebase master featurezrobi to samo, co powyżej.


Teraz na specjalne --onto. Ważną częścią, o której należy pamiętać, jest domyślna wartość, <start>jeśli nie jest określona. Tak więc powyżej, gdybym --ontokonkretnie określił , spowoduje to to samo:

git rebase --onto master master
git rebase --onto master master feature

(Nie używam --ontobez sprecyzowania, <end>ponieważ łatwiej jest przeanalizować mentalnie, nawet jeśli te dwie są takie same, jeśli już są włączone feature).

Aby zobaczyć, dlaczego --ontojest przydatny, oto inny przykład. Powiedzmy, że byłem włączony featurei zauważyłem błąd, który zacząłem naprawiać - ale featurezamiast tego masterprzez pomyłkę:

A--B--F--G master
    \
     C--D--E feature
            \
             H--I bugfix

Chcę przesunąć te zatwierdzenia bugfix, aby nie były już od nich zależne feature. W tej chwili jakikolwiek rodzaj scalenia lub zmiany bazy pokazany powyżej w tej odpowiedzi zajmie trzy featurezatwierdzenia wraz z dwoma bugfixzatwierdzeniami.

Na przykład git rebase master bugfixjest zły. Zasięg <start>do <end>dzieje się zawierać wszystkie rewizje u feature, które są odtwarzanych na górze master:

A--B--F--G master
    \     \
     \     C'--D'--E'--H'--I' bugfix
      \
       C--D--E feature

To, czego tak naprawdę chcemy, to zakres zatwierdzeń od featuredo bugfixodtworzenia na górze master. Po to --ontojest - określenie innego celu „powtórki” niż gałąź „start”:

git rebase --onto master feature bugfix

A--B--F--G master
    \     \
     \     H'--I' bugfix
      \
       C--D--E feature
Izkata
źródło
1

Odświeżenie polega na tym, że przebudowywanie ma miejsce głównie wtedy, gdy chcesz, aby historia zmian wyglądała liniowo, jeśli dwie gałęzie rozwinęły się niezależnie od siebie, w zasadzie przepisuje historię zmian.

tak lubię to robić git rebase --onto <target branch> <start branch> <end branch>

gdzie <target branch>jest gałąź, na której się opierasz, <start branch>zwykle jest gałęzią, z której się <end branch>dzielisz i <end branch>jest gałęzią, na której się opierasz.

jeśli zaczniesz od

A--B--F--G master
    \
     C--D--E feature

i robić

git rebase --onto master master feature

dostaniesz

A--B--F--G master
          \
           C'--D'--E' feature

Inną dobrą rzeczą, o której warto wiedzieć, jest <target branch>ustawienie domyślne, <start branch>dzięki czemu można wykonać tę samą bazę, co

git rebase --onto master feature

Jeśli potrzebujesz więcej pomocy, sprawdź rebase bez łez przewodnika

bez brzoskwini
źródło
Twój wynik wygląda na mylący. rebase powinien pozostawić mastergałąź bez zmian. Po prostu dostajesz „funkcję”, aby rozgałęzić się tak, jak G--C'--D'--E'podczas gdy masterwciąż się zatrzymuje G.
Frank
@Frank, zrobiłem to, aby podkreślić całą historię liniową, ale teraz myślę, że twoja droga jest lepsza. naprawiony.
peachoftree
1
Czy możesz podać przykład, gdzie <target branch>i czym <start branch>się różnią, aby pomóc czytelnikom zrozumieć najbardziej ogólny przypadek?
Rufflewind