Qual é a diferença entre 'git merge' e 'git rebase'?

499

Qual é a diferença entre git mergee git rebase?

Daniel Peñalba
fonte
14
desde a minha resposta foi apagado, visite este link para obter a resposta certa para esta pergunta: git-scm.com/book/en/Git-Branching-Rebasing#The-Basic-Rebase
HiB
6
A propósito, vou adicionar este site. Tudo o que você precisa saber sobre o git learn jogando: pcottle.github.io/learnGitBranching
Rollyng
Leia isto primeiro: git-scm.com/book/en/v2/… Então: git-scm.com/book/en/v2/Git-Branching-Rebasing Você realmente entenderá.
Liber

Respostas:

867

Suponha que originalmente havia 3 commits, A, B, C:

abc

Em seguida, o desenvolvedor Dan criou o commit De o desenvolvedor Ed criou o commit E:

ABCDE

Obviamente, esse conflito deve ser resolvido de alguma forma. Para isso, existem 2 maneiras:

MERGE :

ABCDEM

Ambos confirmam De Eainda estão aqui, mas criamos um commit de mesclagem Mque herda mudanças de ambos De E. No entanto, isso cria uma forma de diamante , que muitas pessoas acham muito confusa.

REBASE :

ABCDER

Criamos commit R, cujo conteúdo real do arquivo é idêntico ao do commit de mesclagem Macima. Mas nos livramos do commit E, como se ele nunca tivesse existido (indicado por pontos - linha de fuga). Devido a essa obliteração, Edeve ser local para o desenvolvedor Ed e nunca deve ter sido enviado para nenhum outro repositório. A vantagem da rebase é que a forma do diamante é evitada e a história permanece em linha reta - a maioria dos desenvolvedores adora isso!

mvp
fonte
53
Boas ilustrações. No entanto, eu não concordo plenamente com o tom positivo de que o rebase é tratado. Tanto na mesclagem quanto na rebase, podem ocorrer conflitos que precisam de resolução manual. E como sempre, quando programadores estão envolvidos, há uma chance não negligenciável de erros, também conhecidos como bugs. Se ocorrer um erro de mesclagem, toda a equipe ou comunidade poderá ver a mesclagem e verificar se um bug foi introduzido lá. A história da rebase permanece no repositório de um desenvolvedor e, mesmo lá, tem vida útil limitada no reflog. Pode parecer melhor, mas ninguém mais pode ver com facilidade o que deu errado.
Uwe Geuder
> "No entanto, isso cria um formato de diamante, que muitas pessoas acham muito confuso." Hum ... você pode elaborar?
9788 Greg Maletic
@GregMaletic: A forma do diamante é uma história não linear. Não sei você, mas não gosto de coisas não lineares em geral. Dito isto, você pode usar a mesclagem com diamantes, se você realmente preferir - ninguém está forçando você.
mvp
1
Embora essa resposta seja extremamente útil, seria melhor se você adicionasse comandos reais do git com arquivos foo.txt simples para reproduzi-lo localmente. Como o último usuário disse, não é óbvio quem está fazendo o rebase.
Vortex
1
@ pferrel: acho que você não entendeu direito. git mergenão intercala as confirmações (mas pode parecer assim git log). Em vez disso, git mergemantém os dois históricos de desenvolvimento de Dan e Ed preservados intactos, como foi visto de cada ponto de vista de cada vez. git rebasefaz parecer que Dan trabalhou primeiro e Ed o seguiu. Nos dois casos (mesclagem e rebase), a árvore de arquivos resultante real é absolutamente idêntica.
Mvp
158

Eu realmente amo esse trecho de 10 coisas que eu odeio no git (ele fornece uma breve explicação para rebase no segundo exemplo):

3. Documentação de baixa qualidade

As páginas de manual são um todo-poderoso "f *** you" 1 . Eles descrevem os comandos da perspectiva de um cientista da computação, não de um usuário. Caso em questão:

git-push – Update remote refs along with associated objects

Aqui está uma descrição para humanos:

git-push – Upload changes from your local repository into a remote repository

Atualização, outro exemplo: (obrigado cgd)

git-rebase – Forward-port local commits to the updated upstream head

Tradução:

git-rebase – Sequentially regenerate a series of commits so they can be 
             applied directly to the head node

E então nós temos

git-merge - Join two or more development histories together

o que é uma boa descrição.


1. sem censura no original

mvw
fonte
O problema não é a linguagem ou se o usuário é um cientista da computação ou não. Embora reformulá-lo de outra maneira ajude a esclarecer os fins (ou seja, o que acontece), ele falha em explicar os meios (como acontece). Git requer entender os meios para entender os fins. É entender precisamente os meios que tornam o Git tão difícil. Como ferramenta, algo usado para simplificar ou reduzir o esforço necessário na tarefa, o Git falha terrivelmente. Infelizmente, muitos desenvolvedores não conseguem perceber isso.
ATL_DEV
128

Pessoalmente, não acho muito útil a técnica de diagramação padrão - as setas sempre parecem apontar o caminho errado para mim. (Eles geralmente apontam para o "pai" de cada confirmação, que acaba atrasando o tempo, o que é estranho).

Para explicar em palavras:

  • Quando você refaz seu ramo para o ramo dele, você diz ao Git para fazer com que pareça que você fez check-out do ramo deles de forma limpa e depois fez todo o seu trabalho a partir daí. Isso cria um pacote limpo e conceitualmente simples de alterações que alguém pode revisar. Você pode repetir esse processo novamente quando houver novas alterações em suas ramificações e sempre terá um conjunto limpo de alterações "na ponta" de suas ramificações.
  • Quando você mescla o ramo deles no ramo, você amarra os dois históricos de galhos nesse momento. Se você fizer isso novamente mais tarde com mais alterações, começará a criar um encadeamento de histórias intercaladas: algumas de suas mudanças, algumas de minhas mudanças, algumas de suas mudanças. Algumas pessoas acham isso confuso ou indesejável.

Por razões que não entendo, as ferramentas da GUI para o Git nunca fizeram muito esforço para apresentar os históricos de mesclagem de maneira mais limpa, abstraindo as mesclagens individuais. Portanto, se você quiser um "histórico limpo", precisará usar o rebase.

Lembro-me de ter lido postagens de blog de programadores que usam apenas rebase e outros que nunca usam rebase.

Exemplo

Vou tentar explicar isso com um exemplo de apenas palavras. Digamos que outras pessoas em seu projeto estejam trabalhando na interface do usuário e você esteja escrevendo documentação. Sem rebase, seu histórico pode ser algo como:

Write tutorial
Merge remote-tracking branch 'origin/master' into fixdocs
Bigger buttons
Drop down list
Extend README
Merge remote-tracking branch 'origin/master' into fixdocs
Make window larger
Fix a mistake in howto.md

Ou seja, mescla e a confirmação da interface do usuário no meio da confirmação da documentação.

Se você reformulou seu código para mestre em vez de mesclá-lo, seria assim:

Write tutorial
Extend README
Fix a mistake in howto.md
Bigger buttons
Drop down list
Make window larger

Todos os seus commits estão na parte superior (mais recente), seguidos pelo restante da masterramificação.

( Aviso: sou o autor da postagem "10 coisas que odeio no Git" mencionada em outra resposta )

Steve Bennett
fonte
42

Embora a resposta aceita e a mais votada sejam ótimas, também acho útil tentar explicar a diferença apenas com palavras:

fundir

  • “Tudo bem, temos dois estados desenvolvidos diferentemente do nosso repositório. Vamos fundi-los juntos. Dois pais, um filho resultante.

rebase

  • “Dê as alterações do ramo principal (qualquer que seja o nome) no meu ramo de recursos. Faça isso fingindo que meu trabalho de destaque começou mais tarde, de fato no estado atual da ramificação principal. ”
  • "Reescreva o histórico das minhas alterações para refletir isso." (é necessário forçá-los a forçar, porque normalmente o controle de versão não interfere no histórico fornecido)
  • “Provavelmente - se as mudanças que eu fiz teve pouco a ver com o meu trabalho - a história realmente não mudará muito, se eu olhar para meus commits diff por diff (você também pode pensar em 'patches').”

resumo: quando possível, o rebase é quase sempre melhor. Facilitando a reintegração ao ramo principal.

Porque? ➝ seu ​​trabalho de recurso pode ser apresentado como um grande 'arquivo de correção' (também conhecido como diff) em relação à ramificação principal, sem a necessidade de 'explicar' vários pais: pelo menos dois, provenientes de uma mesclagem, mas provavelmente muitos mais, se houver houve várias fusões. Diferentemente das mesclagens, várias rebotes não são adicionadas. (outra grande vantagem)

Frank Nocke
fonte
18

A rebase do Git está mais próxima de uma mesclagem. A diferença na rebase é:

  • as confirmações locais são removidas temporariamente da ramificação.
  • executar o git pull
  • insira novamente todos os seus commits locais.

Isso significa que todas as confirmações locais são movidas para o final, depois de todas as confirmações remotas. Se você tiver um conflito de mesclagem, também precisará resolvê-lo.

Willem Franco
fonte
7

Para facilitar a compreensão pode ver a minha figura.

O rebase mudará o hash de confirmação, de modo que, se você quiser evitar muito conflito, use rebase quando o ramo estiver concluído / completo como estável.

insira a descrição da imagem aqui

Nhan Cao
fonte
0

Encontrei um artigo realmente interessante sobre git rebase vs merge , pensei em compartilhá-lo aqui

  • Se você quiser ver o histórico completamente igual ao ocorrido, use a mesclagem. A mesclagem preserva o histórico, enquanto a reorganização o reescreve.
  • A mesclagem adiciona um novo commit ao seu histórico
  • É melhor rebasear para otimizar um histórico complexo, você pode alterar o histórico de consolidação por rebase interativa.
nagendra547
fonte