A documentaçãorebase
do Git para o comando é bastante breve:
--preserve-merges
Instead of ignoring merges, try to recreate them.
This uses the --interactive machinery internally, but combining it
with the --interactive option explicitly is generally not a good idea
unless you know what you are doing (see BUGS below).
Então, o que realmente acontece quando você usa --preserve-merges
? Como ele difere do comportamento padrão (sem esse sinalizador)? O que significa "recriar" uma mesclagem etc.
git
git-rebase
Chris
fonte
fonte
git --rebase-merges
substituirá o antigogit --preserve-merges
. Veja minha resposta abaixoRespostas:
Assim como em uma rebase normal do git, o git
--preserve-merges
primeiro identifica uma lista de confirmações feitas em uma parte do gráfico de confirmação e, em seguida, as replica novamente na parte superior de outra parte. As diferenças com--preserve-merges
relação a quais confirmações são selecionadas para reprodução e como essa reprodução funciona para mesclagem.Para ser mais explícito sobre as principais diferenças entre o rebase normal e a preservação de mesclagem:
git checkout <desired first parent>
), enquanto a rebase normal não precisa se preocupar com isso.Primeiro, tentarei descrever "suficientemente exatamente" o que a rebase
--preserve-merges
faz e, em seguida, haverá alguns exemplos. É claro que se pode começar com os exemplos, se isso parecer mais útil.O algoritmo em "Breve"
Se você realmente deseja conhecer as ervas daninhas, baixe a fonte git e explore o arquivo
git-rebase--interactive.sh
. (O rebase não faz parte do núcleo C do Git, mas é escrito no bash. E, nos bastidores, ele compartilha código com o "rebase interativo".)Mas aqui vou esboçar o que acho que é a essência disso. Para reduzir o número de coisas em que pensar, tomei algumas liberdades. (por exemplo, não tento capturar com 100% de precisão a ordem exata em que os cálculos ocorrem e ignorar alguns tópicos menos centrais, como o que fazer com confirmações que já foram escolhidas entre ramificações).
Primeiro, observe que um rebase sem preservação de mesclagem é bastante simples. É mais ou menos:
Rebase
--preserve-merges
é comparativamente complicado. Aqui está o mais simples que consegui sem perder coisas que parecem muito importantes:Rebase com um
--onto C
argumento deve ser muito semelhante. Em vez de iniciar a reprodução confirmada no HEAD de B, você inicia a reprodução confirmada no HEAD de C. (E use C_new em vez de B_new.)Exemplo 1
Por exemplo, considere o gráfico de confirmação
m é um commit de mesclagem com os pais E e G.
Suponhamos que refizemos o tópico (H) sobre o mestre (C) usando uma base rebase normal, sem preservação de mesclagem. (Por exemplo, tópico de check-out; rebase master .) Nesse caso, o git selecionaria os seguintes commits para reprodução:
e atualize o gráfico de confirmação da seguinte maneira:
(D 'é o equivalente repetido de D, etc.)
Observe que merge commit m não está selecionado para reprodução.
Se, em vez disso,
--preserve-merges
redefinirmos H em cima de C. (Por exemplo, tópico de checkout; rebase --preserve-mescla master .) Nesse novo caso, o git selecionaria os seguintes commits para reprodução:Agora m foi escolhido para repetição. Observe também que os pais de mesclagem E e G foram escolhidos para inclusão antes de se comprometerem m.
Aqui está o gráfico de confirmação resultante:
Novamente, D 'é uma versão escolhida de cereja (ou seja, recriada) de D. O mesmo para E', etc. Todos os commit que não estão no master foram reproduzidos. Tanto E como G (os pais mesclados de m) foram recriados como E 'e G' para servir como pais de m '(após a reformulação, a história da árvore ainda permanece a mesma).
Exemplo 2
Ao contrário do rebase normal, o rebase de preservação de mesclagem pode criar vários filhos da cabeça upstream.
Por exemplo, considere:
Se refazermos o H (tópico) sobre C (mestre), os commits escolhidos para o rebase serão:
E o resultado é assim:
Exemplo 3
Nos exemplos acima, o commit de mesclagem e seus dois pais são confirmados de repetição, em vez dos pais originais que o commit de mesclagem original possui. No entanto, em outras refazer uma consolidação de mesclagem repetida pode acabar com os pais que já estavam no gráfico de consolidação antes da mesclagem.
Por exemplo, considere:
Se restabelecermos o tópico no mestre (preservar mesclagens), as confirmações para reprodução serão
O gráfico de confirmação reescrito terá a seguinte aparência:
Aqui, o commit de mesclagem reproduzido m 'obtém os pais que já existiam no gráfico de commit, ou seja, D (a CABEÇA do mestre) e E (um dos pais do commit de mesclagem original m).
Exemplo 4
A rebase de preservação de mesclagem pode ficar confusa em certos casos de "confirmação vazia". Pelo menos isso é verdade apenas em algumas versões mais antigas do git (por exemplo, 1.7.8.)
Veja este gráfico de confirmação:
Observe que ambos os commit m1 e m2 devem ter incorporado todas as alterações de B e F.
Se tentarmos fazer
git rebase --preserve-merges
de H (tópico) em D (mestre), os seguintes commits serão escolhidos para reprodução:Observe que as mudanças (B, F) unidas em m1 já devem ser incorporadas em D. (Essas mudanças já devem ser incorporadas em m2, porque m2 mescla os filhos de B e F.) Portanto, conceitualmente, reproduzindo m1 em cima de D provavelmente deve ser um no-op ou criar uma confirmação vazia (ou seja, onde a diferença entre revisões sucessivas está vazia).
Em vez disso, no entanto, o git pode rejeitar a tentativa de repetir m1 em cima de D. Você pode receber um erro como este:
Parece que alguém esqueceu de passar uma bandeira para o git, mas o problema subjacente é que o git não gosta de criar confirmações vazias.
fonte
git rebase --preserve-merges
é muito mais lento que umrebase
sem--preserve-merges
. Esse é um efeito colateral de encontrar as confirmações corretas? Existe algo que se possa fazer para acelerar isso? (By the way ... obrigado pela resposta muito detalhada!)O Git 2.18 (Q2 2018) melhorará consideravelmente a
--preserve-merge
opção adicionando uma nova opção."
git rebase
" aprendi "--rebase-merges
" a transplantar toda a topologia do gráfico de confirmação em outro lugar .(Observação: o Git 2.22, segundo trimestre de 2019, na verdade é preterido
--preserve-merge
, e o Git 2.25, primeiro trimestre de 2020, para de anunciar o resultado "git rebase --help
" )Veja cometer 25cff9f , cometer 7543f6f , cometer 1131ec9 , cometer 7ccdf65 , cometer 537e7d6 , cometer a9be29c , cometer 8f6aed7 , cometer 1644c73 , cometer d1e8b01 , cometer 4c68e7d , cometer 9055e40 , cometer cb5206e , cometer a01c2a5 , cometer 2f6b1d1 , cometer bf5c057 (25 de abril de 2018) de Johannes Schindelin (
dscho
) .Veja commit f431d73 (25 Abr 2018) por Stefan Beller (
stefanbeller
) .Veja commit 2429335 (25 de abril de 2018) por Phillip Wood (
phillipwood
) .(Mesclado por Junio C Hamano -
gitster
- na confirmação 2c18e6a , 23 de maio de 2018)git rebase
Agora, a página de manual tem uma seção completa dedicada a refazer o histórico com mesclagens .Extrair:
Consulte commit 1644c73 para um pequeno exemplo:
Qual é a diferença
--preserve-merge
?O compromisso 8f6aed7 explica:
E por "você realmente", o autor se refere a: Johannes Schindelin (
dscho
) , que é o principal motivo (com alguns outros heróis - Hannes, Steffen, Sebastian, ...) de que temos o Git For Windows (embora de volta ao dia - 2009 - isso não foi fácil ).Ele trabalha na Microsoft desde setembro de 2015 , o que faz sentido, considerando que a Microsoft agora usa fortemente o Git e precisa de seus serviços.
Essa tendência começou em 2013, na verdade, com o TFS . Desde então, a Microsoft gerencia o maior repositório Git do planeta ! E, desde outubro de 2018, a Microsoft adquiriu o GitHub .
Você pode ver Johannes falando neste vídeo para o Git Merge 2018 em abril de 2018.
Aqui Jonathan está falando sobre Andreas Schwab, de Suse.
Você pode ver algumas das discussões deles em 2012 .
(O script Git garden shears é mencionado neste patch no commit 9055e40 )
O Git 2.19 (terceiro trimestre de 2018) aprimora a nova
--rebase-merges
opção, fazendo com que ela funcione--exec
.A
--exec
opção " " para "git rebase --rebase-merges
" colocou os comandos exec em locais errados, que foram corrigidos.Consulte commit 1ace63b (09 de agosto de 2018) e commit f0880f7 (06 de agosto de 2018) por Johannes Schindelin (
dscho
) .(Mesclado por Junio C Hamano -
gitster
- in commit 750eb11 , 20 de agosto de 2018)O Git 2.22 (Q2 2019) corrige o uso de refs / reescrito / hierarquia para armazenar estados intermediários de rebase, o que faz inerentemente a hierarquia por árvore de trabalho.
Consulte commit b9317d5 , commit 90d31ff , commit 09e6564 ( 07/03/2019 ) por Nguyễn Thái Ngọc Duy (
pclouds
) .(Mesclado por Junio C Hamano -
gitster
- in commit 917f2cd , 09 abr 2019)O a9be29c (sequenciador: make refs gerado pelo
label
comando worktree-local, 25/04/2018, Git 2.19) é adicionadorefs/rewritten/
como espaço de referência por worktree.Infelizmente (infelizmente), existem alguns lugares que precisam de atualização para garantir que seja realmente por área de trabalho.
Com o Git 2.24 (quarto trimestre de 2019), "
git rebase --rebase-merges
" aprendemos a conduzir diferentes estratégias de mesclagem e a passar opções específicas da estratégia para elas.Veja commit 476998d (04 Set 2019) por Elijah Newren (
newren
) .Consulte confirmar e1fac53 , confirmar a63f990 , confirmar 5dcdd74 , confirmar e145d99 , confirmar 4e6023b , cometer f67336d , cometer a9c7107 , cometer b8c6f24 , cometer d51b771 , cometer c248d32 , cometer 8c1e240 , cometer 5efed0e , cometer 68b54f6 , cometer 2e7bbac , cometer 6180b20 , cometer d5b581f (31 Jul 2019) porJohannes Schindelin (
dscho
) .(Mesclado por Junio C Hamano -
gitster
- no commit 917a319 , 18 de setembro de 2019)Com o Git 2.25 (primeiro trimestre de 2020), a lógica usada para diferenciar as referências locais e do repositório global da árvore de trabalho é corrigida, para facilitar a mesclagem de preservar.
Consulte commit f45f88b , commit c72fc40 , commit 8a64881 , commit 7cb8c92 , commit e536b1f (21 de outubro de 2019) por SZEDER Gábor (
szeder
) .(Incorporado por Junio C Hamano -
gitster
- in commit db806d7 , 10 nov 2019)fonte
--preserve-merges
na verdade não "preserva" as mesclagens como você deseja, é muito ingênua. Isso permite preservar as confirmações de mesclagem e os relacionamentos de confirmação dos pais, além de oferecer a flexibilidade de uma rebase interativa. Esse novo recurso é incrível e, se não fosse por essa resposta bem escrita, eu não saberia!