Compreendendo e memorizando parâmetros do git rebase

12

Até agora, a parte mais confusa do git está sendo rebaseada para outro ramo. Especificamente, são os argumentos da linha de comando que são confusos.

Cada vez que quero refazer um pequeno pedaço de uma ramificação na ponta de outra, preciso revisar a documentação do git rebase e levo de 5 a 10 minutos para entender quais devem ser os três argumentos principais.

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

Qual é uma boa regra geral para me ajudar a memorizar como cada um desses três parâmetros deve ser definido, considerando qualquer tipo de rebase em outro ramo?

Lembre-se de que revi a documentação do git-rebase de novo, e de novo, e de novo, e de novo (e de novo), mas sempre é difícil de entender (como um white paper científico chato ou algo assim). Então, neste ponto, sinto que preciso envolver outras pessoas para me ajudar a entender.

Meu objetivo é que eu nunca precise revisar a documentação desses parâmetros básicos. Não pude memorizá-los até agora, e já fiz muitas repercussões. Portanto, é um pouco incomum que eu tenha sido capaz de memorizar todos os outros comandos e seus parâmetros até agora, mas não me refazendo --onto.

void.pointer
fonte
Você pode definir alguns aliases de git para seus casos de uso comuns ou criar um script do assistente que lembre o significado de cada um dos parâmetros antes de executar o comando.
Rory Hunter
4
Ah, essas opções surpreendentes e pura de opções de comando git. Tão intuitivamente de usar. Sempre um verdadeiro prazer.
JensG

Respostas:

10

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
Izkata
fonte
1

Apenas uma atualização, o rebasing é principalmente para quando você deseja que seu histórico de consolidação pareça linear se dois ramos se desenvolverem independentemente um do outro, basicamente ele reescreve o histórico de consolidação.

do jeito que eu gosto de fazer é git rebase --onto <target branch> <start branch> <end branch>

onde <target branch>é a ramificação na qual você está reestruturando, <start branch>normalmente é a ramificação da qual se <end branch>divide e <end branch>é a ramificação na qual você está reestruturando.

se você começar com

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

e fazer

git rebase --onto master master feature

você vai ter

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

Outra coisa boa a saber é que o <target branch>padrão é que <start branch>você possa fazer o mesmo rebase que

git rebase --onto master feature

se precisar de mais ajuda, consulte o guia Rebase sem lágrimas

peachoftree
fonte
Seu resultado parece enganador. rebase deve deixar o masterpróprio ramo inalterado. Você apenas obtém 'recurso' para ramificar como G--C'--D'--E'enquanto masterainda pára em G.
26414 Frank
@ Frank, eu fiz isso para enfatizar toda a história linear, mas agora acho que você é melhor. fixo.
peachoftree
1
Você pode mostrar um exemplo de onde <target branch>e como <start branch>são diferentes para ajudar os leitores a entender o caso mais geral?
Rufflewind