Vamos pular --onto
por um momento. upstream
e branch
são bem básicos e, na verdade, meio que imitam checkout
e 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 é branch
que 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 rebase
faz 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 master
resulta 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, feature
agora contém código de ambos master
e feature
. Se você não estiver ativo feature
, o segundo argumento pode ser usado para alternar para ele como um atalho: git rebase master feature
fará 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 --onto
especificamente, isso resultaria no mesmo:
git rebase --onto master master
git rebase --onto master master feature
(Eu não uso --onto
sem 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 feature
e notei um bug, que eu comecei a consertar - mas havia ramificado em feature
vez de master
por engano:
A--B--F--G master
\
C--D--E feature
\
H--I bugfix
O que eu quero é "mover" esses commits para bugfix
que eles não sejam mais dependentes feature
. Como é, qualquer tipo de mesclagem ou rebase mostrada acima nesta resposta levará os três feature
commits junto com os dois bugfix
commits.
Por exemplo, git rebase master bugfix
está 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 feature
que bugfix
para ser repetido em cima master
. É --onto
para 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