Quando você usa o Git rebase em vez do Git merge?

1549

Quando é recomendado usar o Git rebase vs. Git merge?

Ainda preciso mesclar após uma nova recuperação bem-sucedida?

Coocoo4Cocoa
fonte
16
isso é bom: atlassian.com/git/tutorials/merging-vs-rebasing
stackexchanger
6
Um problema com as pessoas que gostam de usar rebase é que isso as impede de enviar regularmente seu código. Portanto, querer um histórico limpo os impede de compartilhar seu código, o que eu acho mais importante.
static_rtti
9
@static_rtti: Isso simplesmente não é verdade. Você está usando um fluxo com base em rebase errado se isso impedir que você faça alterações regularmente.
juzzlin
5
É uma pena que as respostas de Andrew Arnott e Pace não tenham sido publicadas anteriormente, pois respondem a essa pergunta de maneira mais abrangente do que as respostas anteriores que já haviam acumulado muitos votos.
Mark Booth

Respostas:

1136

Versão curta

  • A mesclagem pega todas as alterações em uma ramificação e as mescla em outra ramificação em uma consolidação.
  • Rebase diz que quero que o ponto em que eu ramifiquei mude para um novo ponto de partida

Então, quando você usa um dos dois?

Mesclar

  • Digamos que você tenha criado uma ramificação com o objetivo de desenvolver um único recurso. Quando você deseja trazer essas alterações de volta ao mestre, provavelmente deseja mesclar (não se preocupa em manter todos os commits provisórios).

Rebase

  • Um segundo cenário seria se você começasse a fazer algum desenvolvimento e outro desenvolvedor fizesse uma mudança não relacionada. Você provavelmente deseja extrair e, em seguida, fazer uma nova análise para basear suas alterações na versão atual do repositório.
Rob Di Marco
fonte
105
A @Rob mencionou manter confirmações intermediárias ao mesclar. Acredito que, por padrão, a junção do ramo B (um ramo do recurso em que você está trabalhando) no ramo M (o ramo mestre) criará uma confirmação em M para cada confirmação feita em B, uma vez que as duas divergiram. Mas se você mesclar usando a opção --squash, todas as confirmações feitas na ramificação B serão "agrupadas" e mescladas como uma única confirmação na ramificação M, mantendo o log em sua ramificação principal agradável e limpo. Squash é provavelmente o que você deseja se houver vários desenvolvedores trabalhando de forma independente e se fundindo novamente no master.
spaaarky21
19
Acredito que a suposição de @ spaaarky21 sobre a fusão não está correta. Se você mesclar uma ramificação B no mestre M, haverá apenas uma única confirmação em M (mesmo que B tenha várias confirmações), independentemente de você usar uma mesclagem simples ou - squash. O que --squash fará é eliminar a referência a B como pai. Uma boa visualização é aqui: syntevo.com/smartgithg/howtos.html?page=workflows.merge
jpeskin
14
@ jpeskin Não é isso que estou vendo. Acabei de fazer um teste rápido para verificar. Crie um diretório com um arquivo de texto, initum novo repositório, addo arquivo e commit. Fazer check-out de uma nova ramificação de recurso ( checkout -b feature.) Altere o arquivo de texto, confirme e repita para que haja duas novas confirmações na ramificação de recurso. Então checkout mastere merge feature. Em log, vejo meu commit inicial no master, seguido pelos dois que foram mesclados do recurso. Se você merge --squash feature, o recurso for mesclado no mestre, mas não confirmado, o único novo commit no mestre será aquele que você criar.
spaaarky21
21
@ spaaarky21 Parece que nós dois estamos certos. Quando uma mesclagem de avanço rápido é possível (como no seu exemplo), o git usará como padrão todos os commits no ramo de recursos B (ou, como você sugere, você pode usar --squash para combinar em um único commit). Mas no caso em que há duas ramificações divergentes M e B que você está mesclando, o git não incluirá todas as confirmações individuais da ramificação B se mescladas com M (independentemente de você usar --squash).
Jpskin # 28/13
6
Por que o "(você não se preocupa em manter todos os commits provisórios)" ainda nesta resposta? Não fazia sentido em 2009 e não faz sentido agora. Além disso, certamente você só desejaria fazer uma nova reformulação se outro desenvolvedor fizesse alterações relacionadas que você precisava - se elas fizessem alterações não relacionadas, sua ramificação de recursos se fundiria facilmente sem conflitos, e seu histórico seria mantido.
Mark Booth
372

É simples. Com o rebase, você diz usar outro ramo como a nova base para o seu trabalho.

Se você tem, por exemplo, uma ramificação master, cria uma ramificação para implementar um novo recurso e diz o nome cool-feature, é claro que o ramo mestre é a base para o seu novo recurso.

Agora, em um determinado momento, você deseja adicionar o novo recurso implementado na masterramificação. Você pode simplesmente mudar mastere mesclar o cool-featureramo:

$ git checkout master
$ git merge cool-feature

Mas dessa forma, uma nova confirmação fictícia é adicionada. Se você quiser evitar o histórico de espaguete, pode fazer uma nova reformulação :

$ git checkout cool-feature
$ git rebase master

E depois mesclá-lo master:

$ git checkout master
$ git merge cool-feature

Desta vez, como o ramo de tópicos tem as mesmas confirmações do mestre e confirmadas com o novo recurso, a mesclagem será apenas um avanço rápido.

Aldo 'xoen' Giambelluca
fonte
31
but this way a new dummy commit is added, if you want to avoid spaghetti-history- como está ruim?
アレックス
6
Além disso, o sinalizador --no-ff de mesclagem é muito, muito útil.
Aldo 'xoen' Giambelluca
3
@ ア レ ッ ク ス como o usuário Sean Schofieldcoloca em um comentário: "Rebase também é bom, porque uma vez que você eventualmente mescla suas coisas de volta ao master (o que é trivial como já descrito), você as coloca no" topo "do histórico de confirmação. projetos em que os recursos podem ser escritos, mas mesclados várias semanas depois, você não deseja mesclá-los ao mestre porque eles são "recheados" no caminho mestre de volta à história.Pessoalmente, eu gosto de poder fazer o git log e ver esse recurso recente logo no "topo". Observe que as datas de confirmação são preservadas - a rebase não altera essas informações. "
Adrien Seja
4
Eu acho que vale a pena repetir aqui - lembre-se que todos esses termos ( merge, rebase, fast-forward, etc.) são referentes às manipulações específicas de um gráfico acíclico dirigido. Eles se tornam mais fáceis de raciocinar com esse modelo mental em mente.
Roy Tinker
10
@ Aldo Não há nada "limpo" ou "arrumado" em uma história reformulada. Geralmente é imundo e IMHO horrível, porque você não tem idéia do que realmente aconteceu. A história "mais limpa" do Git é a que realmente ocorreu. :)
Marnen Laibow-Koser
269

Para complementar minha própria resposta mencionada por TSamper ,

  • uma rebase geralmente é uma boa idéia para ser feita antes da mesclagem, porque a idéia é que você integre ao seu ramo Yo trabalho do ramo Bno qual irá mesclar.
    Porém, novamente, antes da mesclagem, você resolve qualquer conflito em sua ramificação (ou seja: "rebase", como em "repetir meu trabalho em minha ramificação a partir de um ponto recente da ramificação B).
    Se feito corretamente, a mesclagem subsequente de sua ramificação para ramo Bpode ser rápido.

  • uma mesclagem afeta diretamente a ramificação de destino B, o que significa que as mesclas devem ser triviais; caso contrário, essa ramificação Bpode demorar muito para voltar a um estado estável (hora de resolver todos os conflitos)


o ponto de mesclar após uma rebase?

No caso que eu descrevo, eu me refiro Bao meu ramo, apenas para ter a oportunidade de reproduzir meu trabalho de um ponto mais recente B, mas permanecendo no meu ramo.
Nesse caso, ainda é necessária uma mesclagem para trazer meu trabalho "reproduzido" B.

O outro cenário ( descrito no Git Ready, por exemplo) é trazer o seu trabalho diretamente Batravés de uma nova base (que conserva todos os seus commits legais ou até a oportunidade de reordená-los através de uma nova base interativa).
Nesse caso (em que você rebase enquanto está na ramificação B), você está certo: não é necessária mais nenhuma mesclagem:

Uma árvore Git no padrão quando não mesclamos nem refizemos

rebase1

obtemos rebasing:

rebase3

O segundo cenário é o seguinte: como faço para recuperar o novo recurso no master.

O que quero dizer, ao descrever o primeiro cenário de rebase, é lembrar a todos que uma rebase também pode ser usada como uma etapa preliminar para isso (sendo "colocar o novo recurso de volta no master").
Você pode usar o rebase para primeiro trazer o mestre "para dentro" da ramificação de novos recursos: a rebase repetirá as confirmações de novos recursos do HEAD master, mas ainda no ramo de novos recursos, movendo efetivamente o ponto inicial da ramificação de um antigo mestre confirmado HEAD-master.
Isso permite que você resolva quaisquer conflitos em sua ramificação (ou seja, isoladamente, enquanto permite que o mestre continue evoluindo em paralelo se o estágio de resolução de conflitos demorar muito).
Em seguida, você pode alternar para mestre e merge new-feature(ou rebase new-featurepara masterse você quiser preservar alterações feitas em suanew-feature ramo).

Assim:

  • "rebase vs. merge" pode ser visto como duas maneiras de importar um trabalho, digamos master,.
  • Porém, "reorganizar e mesclar" pode ser um fluxo de trabalho válido para primeiro resolver conflitos isoladamente e, em seguida, recuperar seu trabalho.
VonC
fonte
17
mesclar após a recuperação é um avanço rápido e trivial, sem a necessidade de resolver conflitos.
Obecalp 30/04/09
4
@obelcap: De fato, essa é a idéia: você pega todo o conflito de problemas em seu ambiente (rebase principal dentro do ramo de novos recursos) e depois co-master, mescla o novo recurso: 1 pico-segundo (rápido- encaminhar) se o mestre não tinha evoluções
VonC
27
Rebase também é bom, porque depois que você mescla seu material de volta ao master (o que é trivial como já descrito), você o encontra no "topo" do seu histórico de consolidação. Em projetos maiores, onde os recursos podem ser escritos, mas mesclados várias semanas depois, você não deseja mesclá-los ao mestre, porque eles são "empacotados" no modo mestre de volta à história. Pessoalmente, eu gosto de poder fazer o git log e ver esse recurso recente no topo. Observe que as datas de confirmação são preservadas - o rebase não altera essas informações.
21711 Sean Schofield
3
@ Joe: mentalmente, você está dizendo "repita qualquer uma das minhas alterações (feitas isoladamente no meu ramo particular) em cima desse outro ramo, mas me deixe no meu ramo privado assim que a recuperação for concluída". Essa é uma boa oportunidade para limpar o histórico local, evitando o "comprometimento do ponto de verificação", a bissetriz quebrada e os resultados incorretos da culpa. Veja "Git workflow": sandofsky.com/blog/git-workflow.html
VonC
4
@scoarescoare a chave é ver como as alterações locais são compatíveis no topo da filial upstream mais recente. Se um dos seus commit introduzir um conflito, você o verá imediatamente. Uma mesclagem apresenta apenas um commit (mesclado), o que pode desencadear muitos conflitos sem uma maneira fácil de ver qual deles, entre seus próprios commits locais, adicionou esse conflito. Assim, além de uma história mais limpo, você tem uma visão mais precisa das mudanças que você introduzir, comprometer por Commit (repetido pela rebase), ao contrário de todos as alterações introduzidas pelo ramo montante (despejado em um único merge).
VonC 25/01
229

TL; DR

Se você tiver alguma dúvida, use mesclagem.

Resposta curta

As únicas diferenças entre uma rebase e uma mesclagem são:

  • A estrutura em árvore resultante do histórico (geralmente visível apenas quando se olha para um gráfico de confirmação) é diferente (uma terá ramificações e a outra não).
  • A mesclagem geralmente cria uma confirmação extra (por exemplo, nó na árvore).
  • Mesclar e refazer o tratamento dos conflitos de maneira diferente. O rebase apresentará conflitos, um commit por vez, em que a mesclagem os apresentará todos de uma vez.

Portanto, a resposta mais curta é escolher reorganizar ou mesclar com base no que você deseja que seu histórico seja .

Resposta longa

Existem alguns fatores que você deve considerar ao escolher qual operação usar.

O ramo do qual você está recebendo alterações é compartilhado com outros desenvolvedores fora da sua equipe (por exemplo, código aberto, público)?

Nesse caso, não faça uma nova recuperação. Rebase destrói a ramificação e esses desenvolvedores terão repositórios quebrados / inconsistentes, a menos que eles usem git pull --rebase. Essa é uma boa maneira de perturbar outros desenvolvedores rapidamente.

Qual é a qualificação da sua equipe de desenvolvimento?

Rebase é uma operação destrutiva. Isso significa que, se você não o aplicar corretamente, poderá perder o trabalho comprometido e / ou interromper a consistência dos repositórios de outros desenvolvedores.

Trabalhei em equipes nas quais todos os desenvolvedores vieram de uma época em que as empresas podiam pagar uma equipe dedicada para lidar com ramificações e fusões. Esses desenvolvedores não sabem muito sobre o Git e não querem saber muito. Nessas equipes, não correria o risco de recomendar rebasing por qualquer motivo.

O próprio ramo representa informações úteis

Algumas equipes usam o modelo de ramificação por recurso, em que cada ramificação representa um recurso (ou correção de bug, sub-recurso etc.). Nesse modelo, a ramificação ajuda a identificar conjuntos de confirmações relacionadas. Por exemplo, pode-se reverter rapidamente um recurso revertendo a mesclagem desse ramo (para ser justo, essa é uma operação rara). Ou diferencie um recurso comparando duas ramificações (mais comuns). Rebase destruiria o ramo e isso não seria simples.

Também trabalhei em equipes que usavam o modelo de ramificação por desenvolvedor (todos nós já estivemos lá). Nesse caso, o próprio ramo não transmite nenhuma informação adicional (o commit já tem o autor). Não haveria mal em rebater.

Deseja reverter a mesclagem por algum motivo?

A reversão (como em desfazer) de uma rebase é consideravelmente difícil e / ou impossível (se a rebase tiver conflitos) em comparação com a reversão de uma mesclagem. Se você acha que há uma chance de querer reverter, use a mesclagem.

Você trabalha em equipe? Se sim, você está disposto a adotar uma abordagem de tudo ou nada nesse ramo?

As operações de rebase precisam ser puxadas com um correspondente git pull --rebase. Se você estiver trabalhando sozinho, poderá se lembrar de qual deve usar no momento apropriado. Se você estiver trabalhando em uma equipe, será muito difícil coordenar. É por isso que a maioria dos fluxos de trabalho de rebase recomenda o uso de rebase para todas as mesclagens (e git pull --rebasepara todos os pulls).

Mitos Comuns

A mesclagem destrói o histórico (as polpas são confirmadas)

Supondo que você tenha a seguinte mesclagem:

    B -- C
   /      \
  A--------D

Algumas pessoas afirmam que a mesclagem "destrói" o histórico de consolidação, porque se você examinar o log apenas da ramificação principal (A - D), perderá as importantes mensagens de consolidação contidas em B e C.

Se isso fosse verdade, não teríamos perguntas como esta . Basicamente, você verá B e C, a menos que solicite explicitamente para não vê-los (usando --first-parent). É muito fácil tentar por si mesmo.

Rebase permite mesclagens mais seguras / simples

As duas abordagens se mesclam de maneira diferente, mas não está claro se uma é sempre melhor que a outra e pode depender do fluxo de trabalho do desenvolvedor. Por exemplo, se um desenvolvedor tende a se comprometer regularmente (por exemplo, talvez ele se comprometa duas vezes por dia durante a transição do trabalho para casa), pode haver muitos comprometimentos para um determinado ramo. Muitos desses commits podem não se parecer com o produto final (eu tendem a refatorar minha abordagem uma ou duas vezes por recurso). Se alguém estivesse trabalhando em uma área relacionada do código e tentasse refazer minhas alterações, poderia ser uma operação bastante tediosa.

Rebase é mais legal / mais sexy / mais profissional

Se você gosta de usar o alias rmpara rm -rf"economizar tempo", talvez a redefinição seja a melhor para você.

Meus dois centavos

Eu sempre acho que um dia me depararei com um cenário em que o Git rebase é a ferramenta incrível que resolve o problema. Bem como eu acho que vou encontrar um cenário em que o reflit Git é uma ferramenta incrível que resolve meu problema. Eu trabalho com o Git há mais de cinco anos. Isso não aconteceu.

Histórias confusas nunca foram realmente um problema para mim. Eu nunca apenas leio minha história de commit como um romance emocionante. Na maior parte do tempo, preciso de um histórico. Vou usar a culpa do Git ou o bit do Git de qualquer maneira. Nesse caso, ter a confirmação de mesclagem é realmente útil para mim, porque se a mesclagem introduziu o problema, isso é uma informação significativa para mim.

Atualização (4/2017)

Sinto-me obrigado a mencionar que pessoalmente amoleci o uso do rebase, embora meu conselho geral ainda permaneça. Recentemente, tenho interagido bastante com o projeto Angular 2 Material . Eles usaram o rebase para manter um histórico de consolidação muito limpo. Isso me permitiu ver com muita facilidade qual commit corrigiu um determinado defeito e se esse commit foi incluído ou não em uma liberação. Serve como um ótimo exemplo de uso do rebase corretamente.

Ritmo
fonte
5
Deve ser a resposta validada.
precisa saber é o seguinte
Esta é certamente a melhor resposta. Especialmente com a observação esclarecida na última atualização. Ajuda a manter o histórico do git limpo e claro, mas use-o com segurança.
Zquintana 26/0318
5
Eu principalmente amo essa resposta. Mas: Rebase não faz um histórico "limpo". Faz uma história mais linear, mas não é a mesma coisa, pois quem sabe agora muita "sujeira" que cada commit está ocultando? A história mais limpa e clara do Git é aquela que mantém a ramificação e confirma a integridade.
Marnen Laibow-Koser
3
"Mito comum, você vê os commits B e C": não necessariamente !! Na verdade, você só vê B e C se a mesclagem foi uma mesclagem de avanço rápido e isso só é possível se não houver conflitos. Se houver conflitos, você receberá um único commit! No entanto: você pode mesclar o mestre no recurso primeiro e resolver os conflitos ali; se, então, mesclar o recurso no mestre, você obtém confirmações B e C e um único commit X da (primeira) mesclagem do mestre para o recurso em seu histórico.
Jeremy Benks
muito boa explicação! Deve ter votado mais!
dimmits
185

Muitas respostas aqui dizem que a mesclagem transforma todos os seus commits em um e, portanto, sugerimos o uso de rebase para preservar seus commits. Isto está incorreto. E uma má idéia se você já enviou seus commits .

A mesclagem não anula seus commits. Mesclar preserva a história! (basta olhar para o gitk) Rebase reescreve a história, que é uma coisa ruim depois que você a pressionou .

Use mesclagem - não rebase sempre que você já tiver pressionado.

Aqui está a abordagem de Linus (autor do Git) (agora hospedada em meu próprio blog, recuperada pela Wayback Machine ). É uma leitura muito boa.

Ou você pode ler minha própria versão da mesma idéia abaixo.

Rebaseando uma ramificação no mestre:

  • fornece uma ideia incorreta de como as confirmações foram criadas
  • polui o mestre com um monte de confirmações intermediárias que podem não ter sido bem testadas
  • na verdade, poderia introduzir quebras de compilação nessas confirmações intermediárias devido a alterações que foram feitas para serem controladas entre o momento em que o ramo de tópico original foi criado e quando foi refeito.
  • torna difícil encontrar bons lugares no master para checkout.
  • Faz com que os carimbos de data / hora nas confirmações não se alinhem com sua ordem cronológica na árvore. Portanto, você verá que o commit A precede o commit B no master, mas o commit B foi criado primeiro. (O que?!)
  • Produz mais conflitos, porque as confirmações individuais na ramificação de tópicos podem envolver conflitos de mesclagem que devem ser resolvidos individualmente (mais uma vez na história sobre o que aconteceu em cada confirmação).
  • é uma reescrita da história. Se o ramo que está sendo refeito foi empurrado para qualquer lugar (compartilhado com alguém que não seja você), você estragou todo mundo que tem esse ramo desde que reescreveu o histórico.

Por outro lado, mesclando uma ramificação de tópico no mestre:

  • preserva o histórico de onde as ramificações de tópico foram criadas, incluindo quaisquer mesclagens da mestre para a ramificação de tópico para ajudar a mantê-lo atualizado. Você realmente tem uma idéia precisa de qual código o desenvolvedor estava trabalhando quando estava criando.
  • master é uma ramificação composta principalmente de mesclagens, e cada uma dessas confirmações de mesclagem geralmente são 'bons pontos' no histórico que podem ser verificados com segurança, porque é aí que a ramificação de tópico estava pronta para ser integrada.
  • todas as confirmações individuais da ramificação de tópico são preservadas, incluindo o fato de que elas estavam em uma ramificação de tópico, portanto, isolar essas alterações é natural e você pode detalhar onde necessário.
  • os conflitos de mesclagem precisam ser resolvidos apenas uma vez (no ponto da mesclagem), para que as alterações de confirmação intermediária feitas no ramo de tópico não precisem ser resolvidas independentemente.
  • pode ser feito várias vezes sem problemas. Se você integrar a ramificação do tópico para dominar periodicamente, as pessoas poderão continuar desenvolvendo a ramificação do tópico e ela poderá continuar sendo mesclada independentemente.
Andrew Arnott
fonte
3
Além disso, o git merge possui a opção "--no-ff" (sem avanço rápido) que permite reverter todas as alterações introduzidas por uma certa mesclagem com muita facilidade.
Tiago
3
Apenas para deixar mais claro: você se refere à situação 'sempre que já pressionou' - isso deve ser ousado. O post do Link to Linus é ótimo, esclarece.
Honzajde
2
mas não é uma prática recomendada "atualizar" do mestre para a ramificação do tópico, antes de mesclar a ramificação do tópico para o mestre via PR (para resolver conflitos em sua ramificação, não no mestre)? Estamos fazendo isso assim, para que a maioria das ramificações de tópicos tenha como último commit "mesclar mestre de ramificação em tópico -...", mas aqui é listada como um "recurso" de rebasing e ninguém menciona isso para mesclagem ...?
ProblemsOfSumit
2
@AndrewArnott "A maioria das ramificações de tópicos deve ser capaz de mesclar sem conflitos nas ramificações de destino" Como isso deve ser possível quando 20 desenvolvedores estão trabalhando em 30 ramificações? Haverá mesclagens enquanto você trabalha no seu - então é claro que você precisa atualizar a ramificação de tópicos do destino antes de criar um PR ... não?
ProblemsOfSumit
3
Geralmente não é @Sumit. O Git pode mesclar qualquer direção muito bem, mesmo que as alterações tenham sido feitas em um ou ambos os ramos. Somente quando as mesmas linhas de código (ou muito próximas) forem modificadas em dois ramos, você terá conflitos. Se isso acontecer com freqüência em qualquer equipe, a equipe deve repensar a forma como distribuem o trabalho, pois resolver conflitos é um imposto e diminui a velocidade.
precisa saber é o seguinte
76

TLDR: Depende do que é mais importante - uma história organizada ou uma representação verdadeira da sequência de desenvolvimento

Se um histórico organizado é o mais importante, primeiro você deve fazer uma nova redefinição e depois mesclar suas alterações, para que fique claro exatamente qual é o novo código. Se você já empurrou sua ramificação, não faça uma nova recuperação, a menos que possa lidar com as consequências.

Se a representação verdadeira da sequência for a mais importante, você mesclaria sem rebasear.

Mesclar significa: Criar uma única nova confirmação que mescla minhas alterações no destino. Nota: Esse novo commit terá dois pais - o último commit da sua sequência de commit e o último commit do outro ramo que você está mesclando.

Rebase significa: Crie uma nova série de confirmações, usando meu conjunto atual de confirmações como dicas. Em outras palavras, calcule como seriam as minhas alterações se eu tivesse começado a fazê-las a partir do ponto em que estou refazendo. Após o rebase, portanto, talvez seja necessário testar novamente suas alterações e, durante o rebase, você poderá ter alguns conflitos.

Diante disso, por que você faria uma nova recuperação? Apenas para manter o histórico de desenvolvimento claro. Digamos que você esteja trabalhando no recurso X e, quando terminar, integre suas alterações. O destino agora terá um único commit que diria algo como "Adicionado o recurso X". Agora, em vez de mesclar, se você reformulou e mesclou, o histórico de desenvolvimento de destino conteria todas as confirmações individuais em uma única progressão lógica. Isso facilita a revisão das alterações mais tarde. Imagine como seria difícil revisar o histórico de desenvolvimento se 50 desenvolvedores estivessem mesclando vários recursos o tempo todo.

Dito isto, se você já empurrou a ramificação na qual está trabalhando no upstream, não deve se refazer, mas sim mesclar. Para ramificações que não foram enviadas a montante, faça uma nova análise, teste e mesclagem.

Outro momento em que você pode querer refazer a recuperação é quando deseja se livrar das confirmações de sua ramificação antes de avançar a montante. Por exemplo: Confirmações que introduzem algum código de depuração desde o início e outras confirmações adicionais que limpam esse código. A única maneira de fazer isso é realizando um rebase interativo:git rebase -i <branch/commit/tag>

ATUALIZAÇÃO: Você também deseja usar o rebase quando estiver usando o Git para fazer interface com um sistema de controle de versão que não suporta histórico não linear ( por exemplo, o Subversion ). Ao usar a ponte git-svn, é muito importante que as alterações que você mesclar novamente no Subversion sejam uma lista seqüencial de alterações, além das alterações mais recentes no tronco. Existem apenas duas maneiras de fazer isso: (1) recrie manualmente as alterações e (2) use o comando rebase, que é muito mais rápido.

ATUALIZAÇÃO 2: Uma maneira adicional de pensar em uma rebase é que ela permite um tipo de mapeamento do estilo de desenvolvimento para o estilo aceito no repositório em que você está se comprometendo. Digamos que você gosta de se comprometer em pequenos pedaços. Você tem um commit para corrigir um erro de digitação, um commit para se livrar do código não utilizado e assim por diante. Quando você termina o que precisa fazer, você tem uma longa série de confirmações. Agora, digamos que o repositório que você está comprometendo incentive grandes confirmações, portanto, para o trabalho que você está fazendo, seria de esperar uma ou talvez duas confirmações. Como você pega sua sequência de confirmações e as compacta com o que é esperado? Você usaria um rebase interativo e esmagaria seus commits minúsculos em menos pedaços maiores. O mesmo se aplica se o inverso for necessário - se o seu estilo tiver alguns commits grandes, mas o repositório exigia longas sequências de pequenas confirmações. Você usaria uma rebase para fazer isso também. Se você fez a mesclagem, agora enxertou seu estilo de confirmação no repositório principal. Se houver muitos desenvolvedores, você pode imaginar o quão difícil seria seguir um histórico com vários estilos de confirmação diferentes após algum tempo.

ATUALIZAÇÃO 3: Does one still need to merge after a successful rebase?Sim, você faz. A razão é que uma rebase envolve essencialmente uma "mudança" de confirmações. Como eu disse acima, esses commits são calculados, mas se você tiver 14 commits a partir do ponto de ramificação, assumindo que nada dê errado com sua rebase, você terá 14 commits à frente (do ponto em que está refazendo) depois a rebase está feita. Você tinha uma ramificação antes de uma rebase. Você terá um ramo do mesmo comprimento depois. Você ainda precisa mesclar antes de publicar suas alterações. Em outras palavras, refaça o remanejamento quantas vezes quiser (novamente, apenas se você não tiver promovido suas alterações a montante). Mesclar somente depois que você rebase.

Carl
fonte
1
Uma mesclagem com o mestre pode resultar em um avanço rápido. Em um ramo de recurso, pode haver alguns commits, que possuem bugs menores ou nem são compilados. Se você fizer apenas testes de unidade em uma ramificação de recursos, alguns erros de integração serão exibidos. Antes de mesclar com o mestre, são necessários testes de integração e podem mostrar alguns erros. Se estes forem corrigidos, o recurso poderá ser integrado. Como você não deseja comprometer o código de buggy para dominar, uma rebase parece necessária para impedir um avanço rápido de todas as confirmações.
Mbx
1
O @mbx git mergesuporta a --no-ffopção que o força a fazer uma consolidação de mesclagem.
Gavin S. Yancey
63

Embora a fusão seja definitivamente a maneira mais fácil e comum de integrar mudanças, não é a única: Rebase é um meio alternativo de integração.

Compreendendo a mesclagem um pouco melhor

Quando o Git executa uma mesclagem, ele procura três confirmações:

  • (1) Confirmação ancestral comum. Se você seguir o histórico de duas ramificações em um projeto, elas sempre terão pelo menos uma confirmação em comum: nesse momento, ambas as ramificações tinham o mesmo conteúdo e evoluíram de maneira diferente.
  • (2) + (3) Pontos finais de cada ramificação. O objetivo de uma integração é combinar os estados atuais de duas ramificações. Portanto, suas respectivas revisões mais recentes são de especial interesse. A combinação desses três commits resultará na integração que estamos buscando.

Confirmação de avanço rápido ou mesclagem

Em casos muito simples, um dos dois ramos não tem nenhum novo commit desde que a ramificação aconteceu - seu último commit ainda é o ancestral comum.

Digite a descrição da imagem aqui

Nesse caso, executar a integração é simples: o Git pode simplesmente adicionar todos os commits do outro ramo no topo do commit ancestral comum. No Git, essa forma mais simples de integração é chamada de mesclagem "avanço rápido". Ambos os ramos compartilham exatamente a mesma história.

Digite a descrição da imagem aqui

Em muitos casos, no entanto, os dois ramos avançaram individualmente.

Digite a descrição da imagem aqui

Para fazer uma integração, o Git precisará criar um novo commit que contenha as diferenças entre eles - o commit de mesclagem.

Digite a descrição da imagem aqui

Confirmações humanas e confirmações de mesclagem

Normalmente, um commit é cuidadosamente criado por um ser humano. É uma unidade significativa que envolve apenas as alterações relacionadas e as anota com um comentário.

Um commit de mesclagem é um pouco diferente: em vez de ser criado por um desenvolvedor, ele é criado automaticamente pelo Git. E, em vez de incluir um conjunto de alterações relacionadas, seu objetivo é conectar dois ramos, como um nó. Se você deseja entender uma operação de mesclagem posteriormente, verifique o histórico de ambas as ramificações e o gráfico de consolidação correspondente.

Integrando com Rebase

Algumas pessoas preferem ficar sem esses commits de mesclagem automática. Em vez disso, eles querem que a história do projeto pareça ter evoluído em uma única linha reta. Não resta indicação de que ele foi dividido em várias ramificações em algum momento.

Digite a descrição da imagem aqui

Vamos percorrer uma operação de rebase passo a passo. O cenário é o mesmo dos exemplos anteriores: queremos integrar as alterações do ramo B no ramo A, mas agora usando rebase.

Digite a descrição da imagem aqui

Faremos isso em três etapas

  1. git rebase branch-A // Synchronises the history with branch-A
  2. git checkout branch-A // Change the current branch to branch-A
  3. git merge branch-B // Merge/take the changes from branch-B to branch-A

Primeiro, o Git "desfaz" todas as confirmações no ramo A que ocorreram depois que as linhas começaram a se ramificar (após o comprometimento do ancestral comum). No entanto, é claro, isso não será descartado: em vez disso, você pode pensar nesses commits como "salvos temporariamente".

Digite a descrição da imagem aqui

Em seguida, aplica os commits do ramo B que queremos integrar. Nesse ponto, os dois ramos parecem exatamente iguais.

Digite a descrição da imagem aqui

Na etapa final, as novas confirmações na ramificação A agora são reaplicadas - mas em uma nova posição, em cima das confirmações integradas da ramificação-B (elas são baseadas novamente).

O resultado parece que o desenvolvimento aconteceu em uma linha reta. Em vez de uma consolidação de mesclagem que contém todas as alterações combinadas, a estrutura de consolidação original foi preservada.

Digite a descrição da imagem aqui

Por fim, você obtém uma ramificação limpa da ramificação A, sem confirmações indesejadas e geradas automaticamente.

Nota: Retirado da postagem incrível por git-tower. As desvantagens de rebasetambém é uma boa leitura no mesmo post.

Abdullah Khan
fonte
+1 para diagramas muito legais. Eu sempre quis ilustrar um exemplo de fluxo git da mesma maneira, sem sorte.
Mikayil Abdullayev
60

Antes da mesclagem / rebase:

A <- B <- C    [master]
^
 \
  D <- E       [branch]

Depois git merge master:

A <- B <- C
^         ^
 \         \
  D <- E <- F

Depois git rebase master:

A <- B <- C <- D' <- E'

(A, B, C, D, E e F são confirmados)

Este exemplo e informações muito mais bem ilustradas sobre o Git podem ser encontradas no Tutorial Básico do Git .

guybrush
fonte
30

Esta frase entende:

Em geral, a maneira de obter o melhor dos dois mundos é refazer as alterações locais que você fez, mas ainda não as compartilhou, antes de empurrá-las para limpar sua história, mas nunca refazer tudo o que empurrou para algum lugar .

Fonte: 3.6 Git Branching - Rebasing, Rebase vs. Merge

Joaquin Sargiotto
fonte
25

Esta resposta é amplamente orientada em torno do Git Flow . As tabelas foram gerados com o bom ASCII Generator Tabela , e as árvores de história com este comando maravilhoso ( alias como git lg):

git log --graph --abbrev-commit --decorate --date=format:'%Y-%m-%d %H:%M:%S' --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%ad%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'

As tabelas estão em ordem cronológica inversa para serem mais consistentes com as árvores do histórico. Veja também a diferença entre git mergee git merge --no-ffprimeiro (você geralmente deseja usar git merge --no-ff, pois faz com que seu histórico pareça mais próximo da realidade):

git merge

Comandos:

Time          Branch "develop"             Branch "features/foo"
------- ------------------------------ -------------------------------
15:04   git merge features/foo
15:03                                  git commit -m "Third commit"
15:02                                  git commit -m "Second commit"
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Resultado:

* 142a74a - YYYY-MM-DD 15:03:00 (XX minutes ago) (HEAD -> develop, features/foo)
|           Third commit - Christophe
* 00d848c - YYYY-MM-DD 15:02:00 (XX minutes ago)
|           Second commit - Christophe
* 298e9c5 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git merge --no-ff

Comandos:

Time           Branch "develop"              Branch "features/foo"
------- -------------------------------- -------------------------------
15:04   git merge --no-ff features/foo
15:03                                    git commit -m "Third commit"
15:02                                    git commit -m "Second commit"
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Resultado:

*   1140d8c - YYYY-MM-DD 15:04:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/foo' - Christophe
| * 69f4a7a - YYYY-MM-DD 15:03:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 2973183 - YYYY-MM-DD 15:02:00 (XX minutes ago)
|/            Second commit - Christophe
* c173472 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git merge vs git rebase

Primeiro ponto: sempre mescle os recursos no desenvolvimento, nunca os refaça . Isso é uma consequência da regra de ouro do rebaseamento :

A regra de ouro git rebaseé nunca usá-lo em agências públicas .

Em outras palavras :

Nunca rebase qualquer coisa que você empurrou para algum lugar.

Eu acrescentaria pessoalmente: a menos que seja um ramo de recursos E você e sua equipe estejam cientes das consequências .

Portanto, a questão git mergevs git rebasese aplica quase apenas aos ramos do recurso (nos exemplos a seguir, --no-ffsempre foi usado durante a mesclagem). Observe que, como não tenho certeza de que há uma solução melhor ( existe um debate ), fornecerei apenas como os dois comandos se comportam. No meu caso, prefiro usar git rebase, pois produz uma árvore de histórico mais agradável :)

Entre ramificações de recursos

git merge

Comandos:

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- --------------------------------
15:10   git merge --no-ff features/bar
15:09   git merge --no-ff features/foo
15:08                                                                    git commit -m "Sixth commit"
15:07                                                                    git merge --no-ff features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Resultado:

*   c0a3b89 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 37e933e - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| *   eb5e657 - YYYY-MM-DD 15:07:00 (XX minutes ago)
| |\            Merge branch 'features/foo' into features/bar - Christophe
| * | 2e4086f - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | |           Fifth commit - Christophe
| * | 31e3a60 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | |           Fourth commit - Christophe
* | |   98b439f - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ \            Merge branch 'features/foo' - Christophe
| |/ /
|/| /
| |/
| * 6579c9c - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 3f41d96 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* 14edc68 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git rebase

Comandos:

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09   git merge --no-ff features/foo
15:08                                                                    git commit -m "Sixth commit"
15:07                                                                    git rebase features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Resultado:

*   7a99663 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 708347a - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * 949ae73 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * 108b4c7 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| |           Fourth commit - Christophe
* |   189de99 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| |/
| * 26835a0 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * a61dd08 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* ae6f5fc - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

De developpara uma ramificação de recurso

git merge

Comandos:

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09                                                                    git commit -m "Sixth commit"
15:08                                                                    git merge --no-ff develop
15:07   git merge --no-ff features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Resultado:

*   9e6311a - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 3ce9128 - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| *   d0cd244 - YYYY-MM-DD 15:08:00 (XX minutes ago)
| |\            Merge branch 'develop' into features/bar - Christophe
| |/
|/|
* |   5bd5f70 - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| * | 4ef3853 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | |           Third commit - Christophe
| * | 3227253 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ /            Second commit - Christophe
| * b5543a2 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * 5e84b79 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/            Fourth commit - Christophe
* 2da6d8d - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git rebase

Comandos:

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09                                                                    git commit -m "Sixth commit"
15:08                                                                    git rebase develop
15:07   git merge --no-ff features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Resultado:

*   b0f6752 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 621ad5b - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * 9cb1a16 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * b8ddd19 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/            Fourth commit - Christophe
*   856433e - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\            Merge branch 'features/foo' - Christophe
| * 694ac81 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 5fd94d3 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* d01d589 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

Notas laterais

git cherry-pick

Quando você só precisa de uma confirmação específica, git cherry-pické uma boa solução (a -xopção anexa uma linha que diz " (cereja escolhida na confirmação ...) " ao corpo da mensagem de confirmação original, portanto, geralmente é uma boa ideia usá-la - git log <commit_sha1>para ver isto):

Comandos:

Time           Branch "develop"              Branch "features/foo"                Branch "features/bar"
------- -------------------------------- ------------------------------- -----------------------------------------
15:10   git merge --no-ff features/bar
15:09   git merge --no-ff features/foo
15:08                                                                    git commit -m "Sixth commit"
15:07                                                                    git cherry-pick -x <second_commit_sha1>
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Resultado:

*   50839cd - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 0cda99f - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * f7d6c47 - YYYY-MM-DD 15:03:00 (XX minutes ago)
| |           Second commit - Christophe
| * dd7d05a - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * d0d759b - YYYY-MM-DD 15:05:00 (XX minutes ago)
| |           Fourth commit - Christophe
* |   1a397c5 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| |/
|/|
| * 0600a72 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * f4c127a - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* 0cf894c - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git pull --rebase

Não sei se posso explicar melhor do que Derek Gourlay ... Basicamente, use em git pull --rebasevez de git pull:) O que está faltando no artigo, porém, é que você pode ativá-lo por padrão :

git config --global pull.rebase true

git rerere

Mais uma vez, bem explicado aqui . Simplificando, se você ativá-lo, não precisará mais resolver o mesmo conflito várias vezes.

sp00m
fonte
15

O livro Pro Git tem uma explicação realmente boa na página de rebasing .

Basicamente, uma mesclagem leva dois commits e os combina.

Uma rebase irá para o ancestral comum nos dois e aplicará as alterações gradualmente umas sobre as outras. Isso cria uma história mais "limpa" e mais linear.

Mas quando você se refaz, você abandona as confirmações anteriores e cria novas. Portanto, você nunca deve refazer um repositório que é público. As outras pessoas que trabalham no repositório o odiarão.

Por essa razão, eu quase me uno exclusivamente. Em 99% das vezes, meus ramos não diferem tanto; portanto, se houver conflitos, é apenas em um ou dois lugares.

xero
fonte
1
Mesclagens não combinam confirmações - isso seria reescrever o histórico. Rebase faz isso.
kellyfj
4

O Git rebase é usado para tornar os caminhos de ramificação no histórico mais limpos e a estrutura do repositório linear.

Ele também é usado para manter as ramificações criadas por você em particular, pois, depois de refazer e empurrar as alterações para o servidor, se você excluir sua ramificação, não haverá evidências de ramificações nas quais você trabalhou. Portanto, sua filial agora é sua preocupação local.

Depois de fazer o rebase, também nos livramos de um commit extra que costumávamos ver se fazemos uma mesclagem normal.

E sim, ainda é necessário fazer a mesclagem após um rebase bem-sucedido, pois o comando rebase apenas coloca seu trabalho no ramo que você mencionou durante o rebase, digamos mestre, e faz o primeiro commit do seu ramo como descendente direto do ramo mestre . Isso significa que agora podemos fazer uma junção de avanço rápido para trazer alterações dessa ramificação para a ramificação mestre.

cvibha
fonte
4

Se você é apenas um desenvolvedor, pode usar rebase em vez de mesclar para ter um histórico claro

insira a descrição da imagem aqui

yoAlex5
fonte
3

Alguns exemplos práticos, um pouco conectados ao desenvolvimento em larga escala, onde o Gerrit é usado para integração de revisão e entrega:

Eu mesclo quando elevo minha ramificação de recursos para um novo mestre remoto. Isso proporciona um trabalho mínimo de melhoria e é fácil acompanhar o histórico do desenvolvimento de recursos, por exemplo, no gitk .

git fetch
git checkout origin/my_feature
git merge origin/master
git commit
git push origin HEAD:refs/for/my_feature

Mesclar quando preparo uma confirmação de entrega.

git fetch
git checkout origin/master
git merge --squash origin/my_feature
git commit
git push origin HEAD:refs/for/master

Eu me refiz quando minha confirmação de entrega falha na integração por qualquer motivo e preciso atualizá-la para um novo mestre remoto.

git fetch
git fetch <gerrit link>
git checkout FETCH_HEAD
git rebase origin/master
git push origin HEAD:refs/for/master
Martin G
fonte
3

Foi explicado muitas vezes o que é rebase e o que é mesclagem, mas quando você deve usar o quê?

Quando você deve usar o rebase?

  • quando você não empurrou o ramo / ninguém mais está trabalhando nele
  • você quer a história completa
  • você deseja evitar todas as mensagens de confirmação "mescladas .." geradas automaticamente

À medida que o Git rebase muda o histórico. Portanto, você não deve usá-lo quando alguém estiver trabalhando no mesmo ramo / se você o tiver pressionado. Mas se você tiver uma filial local, poderá fazer uma mesclagem do mestre de rebase antes de mesclar sua ramificação novamente no mestre para manter um histórico mais limpo. Fazendo isso, depois de mesclar na ramificação principal, não será visível que você tenha usado uma ramificação na ramificação principal - o histórico é "mais limpo", pois você não possui "mesclado .." gerado automaticamente, mas ainda tem o histórico completo em sua ramificação principal sem ter confirmado automaticamente "mesclado ..".

Certifique-se, porém, git merge feature-branch --ff-onlyde garantir que não haja conflitos ao criar um único commit ao mesclar seu recurso de volta ao main. Isso é interessante se você estiver usando ramificações de recursos para todas as tarefas em que trabalha, à medida que obtém o histórico da ramificação de recursos, mas não um commit "mesclado .."

Um segundo cenário seria, se você ramificasse de uma ramificação e desejasse saber o que mudou na ramificação principal. Rebase fornece as informações, pois inclui todas as confirmações.

Quando você deve usar a mesclagem?

  • quando você pressionou o ramo / outros estão trabalhando nele também
  • você não precisa do histórico completo
  • simplesmente mesclar é bom o suficiente para você

Quando você não precisa ou deseja ter todo o histórico de uma ramificação de recurso em sua ramificação principal ou se outras pessoas estão trabalhando na mesma ramificação / você o pressionou. Se você ainda deseja ter o histórico, basta mesclar o mestre na ramificação do recurso antes de mesclar a ramificação do recurso no mestre. Isso resultará em uma mesclagem de avanço rápido, na qual você tem o histórico da ramificação de recursos em seu mestre (incluindo a consolidação de mesclagem que estava em sua ramificação de recursos porque você mesclou o mestre a ela).

Jeremy Benks
fonte
-4

Quando uso git rebase? Quase nunca, porque reescreve a história. git mergeé quase sempre a escolha preferível, porque respeita o que realmente aconteceu no seu projeto.

Marnen Laibow-Koser
fonte
1
@ benjaminhull Obrigado! - exceto espero que minha resposta seja baseada em fatos. A opinião da IMHO tem pouco lugar nesse tipo de coisa: é um fato que perder sua história real dificulta a vida mais tarde.
Marnen Laibow-Koser
1
Aceita. Mesclar nunca vai levar a história corrompido etc. (quando você rebase seus commits difundidas)
surfrider