Vamos pular --ontopor um momento. upstreame branchsão bem básicos e, na verdade, meio que imitam checkoute branch- o segundo argumento é opcional:
git branch <newbranch>
git branch <newbranch> <base>
git checkout -b <newbranch>
git checkout -b <newbranch> <base>
git rebase <upstream>
git rebase <upstream> <branch>
(Com exceção, os nomes desses argumentos rebase, "a montante" e "filial" não são muito descritivo IMO I tipicamente pensar neles como peachoftree,. <start>E <end>, que é como eu vou estar usando-os: git rebase <start> <end>)
Quando o segundo ramo é omitido, o resultado é quase o mesmo que primeiro fazer check-out desse ramo e, em seguida, fazê-lo como se você não tivesse especificado esse ramo. A exceção é branchque não altera sua ramificação atual:
git checkout <base> && git branch <newbranch> && git checkout <previous_branch>
git checkout <base> && git checkout -b <newbranch>
git checkout <end> && git rebase <start>
Quanto a entender o que rebasefaz quando invocado, comecei pensando nele como um tipo especial de mesclagem. Não é verdade, mas ajudou quando começou a entender o rebase. Para emprestar o exemplo de peachoftree:
A--B--F--G master
\
C--D--E feature
A git merge masterresulta nisso:
A--B--F-----G master
\ \
C--D--E--H feature
Enquanto a git rebase master(enquanto estiver no ramo feature!) Resulta nisso:
A--B--F--G master
\
C'--D'--E' feature
Nos dois casos, featureagora contém código de ambos mastere feature. Se você não estiver ativo feature, o segundo argumento pode ser usado para alternar para ele como um atalho: git rebase master featurefará o mesmo que acima.
Agora, para o especial --onto. A parte importante a ser lembrada é que o padrão é <start>se não for especificado. Então, acima, se eu especificasse --ontoespecificamente, isso resultaria no mesmo:
git rebase --onto master master
git rebase --onto master master feature
(Eu não uso --ontosem especificar <end>simplesmente porque é mais fácil analisar mentalmente, mesmo que esses dois sejam iguais se já estiverem ativados feature.)
Para ver por que --ontoé útil, aqui está um exemplo diferente. Digamos que eu estava ligado featuree notei um bug, que eu comecei a consertar - mas havia ramificado em featurevez de masterpor engano:
A--B--F--G master
\
C--D--E feature
\
H--I bugfix
O que eu quero é "mover" esses commits para bugfixque eles não sejam mais dependentes feature. Como é, qualquer tipo de mesclagem ou rebase mostrada acima nesta resposta levará os três featurecommits junto com os dois bugfixcommits.
Por exemplo, git rebase master bugfixestá errado. Ocorre <start>que o intervalo <end>inclui todos os commits de feature, que são reproduzidos em cima de master:
A--B--F--G master
\ \
\ C'--D'--E'--H'--I' bugfix
\
C--D--E feature
O que nós queremos realmente é o intervalo de commits de featureque bugfixpara ser repetido em cima master. É --ontopara isso - especificar um destino de "repetição" diferente do ramo "iniciar":
git rebase --onto master feature bugfix
A--B--F--G master
\ \
\ H'--I' bugfix
\
C--D--E feature