Saltiamo --onto
per il momento. upstream
e branch
sono piuttosto semplici, e in realtà ordinano - imitano checkout
e branch
- il secondo argomento è facoltativo:
git branch <newbranch>
git branch <newbranch> <base>
git checkout -b <newbranch>
git checkout -b <newbranch> <base>
git rebase <upstream>
git rebase <upstream> <branch>
(A parte questo, i nomi di questi argomenti in rebase
, "upstream" e "branch" non sono IMO molto descrittivi. In genere li considero come peachoftree, <start>
e <end>
, che è come li userò: git rebase <start> <end>
)
Quando il secondo ramo viene omesso, il risultato è quasi lo stesso di prima controllare quel ramo e poi farlo come se non avessi specificato quel ramo. L'eccezione è branch
che non cambia il tuo ramo attuale:
git checkout <base> && git branch <newbranch> && git checkout <previous_branch>
git checkout <base> && git checkout -b <newbranch>
git checkout <end> && git rebase <start>
Per capire cosa fa rebase
quando invocato, ho iniziato a pensarlo come un tipo speciale di unione. Non è davvero, ma è stato utile quando ho iniziato a capire il rebase. Per prendere in prestito l'esempio di peachoftree:
A--B--F--G master
\
C--D--E feature
Un git merge master
ha come risultato:
A--B--F-----G master
\ \
C--D--E--H feature
Mentre un get rebase master
(mentre sul ramo feature
!) risulta in questo:
A--B--F--G master
\
C'--D'--E' feature
In entrambi i casi, feature
ora contiene il codice sia da master
sia da feature
. Se non sei su feature
, il secondo argomento può essere utilizzato per passare ad esso come una scorciatoia: git rebase master feature
farà la stessa cosa di cui sopra.
Ora, per lo speciale --onto
. La parte importante da ricordare con questo è che per impostazione predefinita <start>
se non specificato. Così sopra, se specificassi specificamente --onto
, questo risulterebbe nello stesso modo:
git rebase --onto master master
git rebase --onto master master feature
(Non uso --onto
senza specificare <end>
semplicemente perché è più facile da analizzare mentalmente, anche se si pensa che siano uguali se già su feature
.)
Per capire perché --onto
è utile, ecco un esempio diverso. Diciamo che ero su feature
e ho notato un bug, che ho poi iniziato a risolvere, ma che per errore era derivato da feature
invece di master
:
A--B--F--G master
\
C--D--E feature
\
H--I bugfix
Quello che voglio è "spostare" questi commit per bugfix
in modo che non dipendano più da feature
. Così com'è, qualsiasi tipo di unione o di rebase mostrata sopra in questa risposta impiegherà il tre% difeature
a commit con i due commit di bugfix
.
Ad esempio, git rebase master bugfix
è sbagliato. L'intervallo da <start>
a <end>
capita di includere tutti i commit da feature
, che vengono riprodotti su master
:
A--B--F--G master
\ \
\ C'--D'--E'--H'--I' bugfix
\
C--D--E feature
Ciò che in realtà vogliamo è l'intervallo di commit da feature
a bugfix
da riprodurre su master
. Questo è ciò che --onto
è per: specificare un target "replay" diverso dal ramo "start":
git rebase --onto master feature bugfix
A--B--F--G master
\ \
\ H'--I' bugfix
\
C--D--E feature