Percebi que os dois blocos dos seguintes comandos git têm comportamentos diferentes e não entendo o porquê.
Eu tenho um A
e um B
ramo que diverge com umcommit
---COMMIT--- (A)
\
--- (B)
Quero refazer a B
ramificação no último A
(e ter o commit na B
ramificação)
---COMMIT--- (A)
\
--- (B)
Não tem problema se eu fizer:
checkout B
rebase A
Mas se eu fizer:
checkout B
rebase --onto B A
Não funciona, nada acontece. Não entendo por que os dois comportamentos são diferentes.
O cliente phpstorm git usa a segunda sintaxe e, portanto, parece-me completamente quebrado, é por isso que peço esse problema de sintaxe.
git
git-rebase
Xmanoux
fonte
fonte
Respostas:
tl; dr
A sintaxe correta a ser reformulada
B
após oA
usogit rebase --onto
no seu caso é:ou rebase
B
apósA
iniciar a confirmação que é o pai doB
referenciado comB^
ouB~1
.Se você estiver interessado na diferença entre
git rebase <branch>
egit rebase --onto <branch>
continue lendo.O Quick: git rebase
git rebase <branch>
vai rebase o ramo que você tem atualmente check-out, referenciado porHEAD
, no topo do mais recente commit que está acessível a partir<branch>
, mas não a partirHEAD
.Este é o caso mais comum de rebaseamento e, sem dúvida, o que exige menos planejamento antecipado.
Neste exemplo,
F
eG
são confirmações acessíveis,branch
mas não acessíveisHEAD
. Dizendogit rebase branch
levaráD
, que é o primeiro comprometer depois do ponto de ramificação e rebase-lo (ou seja, alterar o seu pai ) no topo da mais recente commit acessível a partirbranch
mas não doHEAD
que éG
.The Precise: git rebase --onto com 2 argumentos
git rebase --onto
permite que você renasça a partir de uma confirmação específica . Concede a você controle exato sobre o que está sendo reformulado e onde. Isso é para cenários em que você precisa ser preciso.Por exemplo, vamos imaginar que precisamos nos refazer
HEAD
precisamente antes deF
começarE
. Estamos interessados apenas em entrarF
em nosso ramo de trabalho e, ao mesmo tempo, não queremos mantê-D
lo porque ele contém algumas alterações incompatíveis.Nesse caso, diríamos
git rebase --onto F D
. Isso significa:Em outras palavras, altere o pai de
E
deD
paraF
. A sintaxe degit rebase --onto
é entãogit rebase --onto <newparent> <oldparent>
.Outro cenário em que isso é útil é quando você deseja remover rapidamente algumas confirmações da ramificação atual sem ter que fazer uma nova análise interativa :
Neste exemplo, a fim de remover
C
eE
da sequência, você diriagit rebase --onto B E
ou rebase,HEAD
além deB
onde estava o pai antigoE
.The Surgeon: git rebase --onto com 3 argumentos
git rebase --onto
pode dar um passo adiante em termos de precisão. De fato, ele permite que você refaça um intervalo arbitrário de confirmações sobre outras.Aqui está um exemplo:
Nesse caso, queremos refazer o intervalo exato
E---H
em cimaF
, ignorando para ondeHEAD
está apontando atualmente. Podemos fazer isso dizendogit rebase --onto F D H
, o que significa:A sintaxe de
git rebase --onto
com um intervalo de confirmações se tornagit rebase --onto <newparent> <oldparent> <until>
. O truque aqui é lembrar que o commit referenciado por<until>
está incluído no intervalo e se tornará o novoHEAD
após a conclusão da recuperação.fonte
<oldparent>
nome será quebrado se as duas partes do intervalo estiverem em ramificações diferentes. Geralmente é: "Inclua todas as confirmações acessíveis,<until>
mas exclua todas as confirmações acessíveis<oldparent>
".git rebase --onto <newparent> <oldparent>
é a melhor explicação para o comportamento --no que eu já vi!--onto
opção, mas isso deixou tudo claro! Eu nem entendo como eu não poderia ter entendido isso antes: D Obrigado por excelente "tutorial" :-)É tudo o que você precisa saber para entender
--onto
:Você está alternando um pai em um commit, mas não está fornecendo o sha do commit, apenas o sha do pai atual (antigo).
fonte
Em breve, dado:
Qual é o mesmo que (porque
--onto
leva um argumento):Significa rebase commit no intervalo (D, H] em cima de F. Observe que o range é exclusivo à esquerda. É exclusivo porque é mais fácil especificar o 1º commit digitando, por exemplo,
branch
para deixargit
encontrar o 1º commit divergente,branch
ou seja, oD
que leva aH
.Caso OP
Pode ser alterado para um único comando:
O que parece erro aqui é o posicionamento,
B
que significa "mover alguns commits que levam a ramificaçãoB
por cimaB
". A questão é o que "alguns commits" são. Se você adicionar-i
sinalizador, verá que é um único commit apontado porHEAD
. A confirmação foi ignorada porque já foi aplicada ao--onto
destinoB
e, portanto, nada acontece.O comando não faz sentido, em qualquer caso em que o nome do ramo seja repetido assim. Isso ocorre porque o intervalo de confirmações será de algumas confirmações que já estão nessa ramificação e, durante a reformulação, todas elas serão ignoradas.
Mais explicações e uso aplicável de
git rebase <upstream> <branch> --onto <newbase>
.git rebase
padrões.Expande para:
Check-out automático após o rebase.
Quando usado de maneira padrão, como:
Você não notará que, após o rebase,
git
passarbranch
para o commit rebased mais recente e o fazgit checkout branch
(consulte ogit reflog
histórico). O que é interessante quando o segundo argumento é o hash de confirmação, em vez disso, a rebase do nome da ramificação ainda funciona, mas como não há ramificação a ser movida, você acaba em "HEAD desanexado" em vez de fazer check-out na ramificação movida.Omita confirmações divergentes primárias.
O
master
in--onto
é retirado do 1ºgit rebase
argumento.Tão prático que pode ser qualquer outro commit ou ramo. Dessa forma, você pode limitar o número de confirmações de rebase, pegando as mais recentes e deixando as confirmações divergentes primárias.
Vai rebase única confirmação apontado por
HEAD
quemaster
e acabam em "CABEÇA destacada".Evite checkouts explícitos.
O padrão
HEAD
oucurrent_branch
argumento é contextualmente retirado do local em que você está. É por isso que a maioria das pessoas faz checkout para ramificar as quais deseja refazer. Mas quando o segundo argumento de rebase é fornecido explicitamente, você não precisa fazer check-out antes de rebase para passá-lo de maneira implícita.Isso significa que você pode recuperar as confirmações e ramificações de qualquer lugar. Então, juntamente com o checkout automático após o rebase.você não precisa fazer check-out separado da ramificação rebatida antes ou depois da rebase.
fonte
Simplificando,
git rebase --onto
seleciona um intervalo de confirmações e as refaz na confirmação fornecida como parâmetro.Leia as páginas de manual
git rebase
, procure por "no". Os exemplos são muito bons:Nesse caso, você diz ao git para refazer as confirmações de
topicA
para otopicB
topomaster
.fonte
Para entender melhor a diferença entre
git rebase
egit rebase --onto
é bom saber quais são os comportamentos possíveis para os dois comandos.git rebase
nos permitem mover nossos commits no topo do ramo selecionado. Como aqui:e o resultado é:
git rebase --onto
é mais preciso. Ele nos permite escolher o commit específico onde queremos começar e também onde queremos terminar. Como aqui:e o resultado é:
Para obter mais detalhes, recomendo que você verifique meu próprio artigo sobre o git rebase - resumo geral
fonte
git rebase --onto F D
como filho fixo do pai de D como F , não podemos?Para
onto
você precisar de dois ramos adicionais. Com esse comando, você pode aplicar confirmaçõesbranchB
baseadas embranchA
outra ramificação, por exemplomaster
. Na amostra abaixo,branchB
é baseadobranchA
e você deseja aplicar as alterações debranchB
onmaster
sem aplicar as alterações debranchA
.usando os comandos:
você seguirá a hierarquia de confirmação.
fonte
rebase --onto branchA branchB
, isso colocaria todo o ramo principal na cabeça do ramoA?checkout branchB: rebase --onto master branchA
?Há outro caso em que
git rebase --onto
é difícil entender: quando você refaz um commit resultante de um seletor de diferença simétrica (os três pontos '...
')O Git 2.24 (quarto trimestre de 2019) faz um trabalho melhor ao gerenciar esse caso:
Consulte commit 414d924 , commit 4effc5b , commit c0efb4c , commit 2b318aa (27 de agosto de 2019) e commit 793ac7e , commit 359eceb (25 de agosto de 2019) de Denton Liu (
Denton-L
) .Ajudado por: Eric Sunshine (
sunshineco
) , Junio C Hamano (gitster
) , Ævar Arnfjörð Bjarmason (avar
) e Johannes Schindelin (dscho
) .Consulte commit 6330209 , commit c9efc21 (27 de agosto de 2019) e commit 4336d36 (25 de agosto de 2019) por Ævar Arnfjörð Bjarmason (
avar
).Ajudado por: Eric Sunshine (
sunshineco
) ,Junio C Hamano (gitster
) , Ævar Arnfjörð Bjarmason (avar
) e Johannes Schindelin (dscho
) .(Mesclado por Junio C Hamano -
gitster
- in commit 640f9cd , 30 set 2019)Neste ponto, leia " Quais são as diferenças entre pontos duplos '
..
' e pontos triplos"...
"nos intervalos de confirmação do Git diff? "Aqui: "
master...
" refere-se amaster...HEAD
, que éB
: HEAD está do lado HEAD (atualmente com check-out): você está refazendo oB
.O que você está refazendo? Qualquer commit que não esteja no master e acessível a partir do
side
branch: existe apenas um commit que se encaixa nessa descrição:D
... que já está no topoB
!Novamente, antes do Git 2.24, esse
rebase --onto
resultado seriaD
sempre rebatizado, não importa o quê.Isso é semelhante ao
rebase --onto B A
do OP, que não fez nada.e o comando com falha foi
A
rebase --onto C F topic
significa qualquer commit depoisF
, acessível portopic
HEAD: isto éG
apenas, nãoF
ele próprio.O avanço rápido nesse caso incluiria
F
na ramificação rebaseada, o que está errado.fonte