Anexo: Diferença entre git merge e git rebase

5 min

Contexto

Neste exemplo, temos um repositório com uma branch principal main contendo um ficheiro de base fichier1.txt e um primeiro commit inicial. A partir de main, criamos duas branches, branche1 e branche2, cada uma destinada a testar respetivamente rebase e merge. Depois, duas branches de trabalho adicionais são criadas, branche-rebase a partir de branche1 e branche-merge a partir de branche2, para lhes acrescentar modificações.

Histórico inicial

O projeto começa com um repositório contendo um único commit em main, correspondente à criação do ficheiro fichier1.txt:

plaintext
(main)
A               # Commit inicial com fichier1.txt

No commit A, acrescentámos o ficheiro fichier1.txt com conteúdo inicial.

Depois, duas novas branches são criadas a partir de main:

  1. branche1: destinada a acolher branche-rebase para testar git rebase.
  2. branche2: destinada a acolher branche-merge para testar git merge.

Trabalho em cada branch de trabalho

Em cada branch de trabalho (branche-rebase e branche-merge), fazemos três commits distintos. Eis os commits em detalhe para cada branch:

plaintext
(main)
A

(branche-rebase)
       \
        D---E---F   # Commits acrescentados em branche-rebase

(branche-merge)
       \
        G---H---I   # Commits acrescentados em branche-merge
  1. Commits em branche-rebase:

    • Commit D: criação do ficheiro fichier-2-rebase.txt com o conteúdo inicial "Modification 1 dans branche-rebase".
    • Commit E: adição de "Modification 2 dans branche-rebase" no mesmo ficheiro fichier-2-rebase.txt.
    • Commit F: adição de "Modification 3 dans branche-rebase" no mesmo ficheiro fichier-2-rebase.txt.
  2. Commits em branche-merge:

    • Commit G: criação do ficheiro fichier-2-merge.txt com o conteúdo inicial "Modification 1 dans branche-merge".
    • Commit H: adição de "Modification 2 dans branche-merge" no mesmo ficheiro fichier-2-merge.txt.
    • Commit I: adição de "Modification 3 dans branche-merge" no mesmo ficheiro fichier-2-merge.txt.

Estes commits acrescentam conteúdo idêntico, mas em ficheiros diferentes (fichier-2-rebase.txt e fichier-2-merge.txt), para permitir uma comparação clara entre merge e rebase.


Etapa 1: fusão de branche-merge em branche2 com git merge

Para integrar as modificações de branche-merge em branche2, usamos o comando git merge em branche2. Esta operação cria um commit de fusão que conserva um histórico completo e inclui os commits da branch de trabalho sem os reorganizar.

O histórico depois do merge:

plaintext
(branche2)
A-------J        # J é o commit de fusão
 \       |
  \      |
   G---H---I     # branche-merge conserva o seu histórico distinto
  • Explicação dos commits:
    • Commit J: commit de fusão que combina o conteúdo de branche2 com as modificações de branche-merge (G, H, I) sem as deslocar nem modificar a ordem.
  • Observação: com git merge, o histórico mostra um « ponto de junção » que indica visualmente onde branche-merge foi fundida em branche2. Isto conserva um histórico completo e distinto para cada branch, o que é muitas vezes útil em projetos colaborativos.

Etapa 2: integração de branche-rebase em branche1 com git rebase

Para integrar as modificações de branche-rebase em branche1, usamos o comando git rebase. Ao contrário do merge, o rebase reposiciona os commits (D, E, F) de branche-rebase como se tivessem sido criados depois do último commit de branche1 (A).

O histórico depois do rebase:

plaintext
(branche1)
A---D'---E'---F'   # Commits de branche-rebase reaplicados no fim de branche1
  • Explicação dos commits:
    • Commits D', E', F': commits reproduzidos de branche-rebase aplicados linearmente a seguir a A em branche1.
  • Observação: com git rebase, os commits de branche-rebase são reorganizados para formar um histórico linear sem « ponto de junção », como se tivessem sido acrescentados diretamente depois do commit inicial A. Isto simplifica o histórico tornando-o mais limpo, mas pode mascarar o caminho das branches de trabalho iniciais.

Comparação final

As diferenças observadas nos logs Git permitem compreender melhor os usos específicos de merge e rebase.

  • git merge:

    • Efeito: mantém um histórico completo com um commit de fusão que marca a junção das branches.
    • Vantagem: ideal para seguir um histórico completo em projetos colaborativos, porque cada junção é visível.
    • Inconveniente: o histórico pode tornar-se complexo com muitas junções, sobretudo em projetos com várias branches.
  • git rebase:

    • Efeito: reorganiza os commits para os colocar linearmente no fim da branch principal, sem criar um commit de fusão.
    • Vantagem: ideal para um histórico linear e limpo, ao minimizar as junções. Isto é muitas vezes preferido em projetos pequenos ou para limpar o histórico antes de o partilhar.
    • Inconveniente: pode mascarar o caminho das branches de trabalho, o que pode ser um problema se várias pessoas trabalham nas mesmas branches.

Resumo

ComandoHistóricoCaso de utilização ideal
git mergeHistórico completo com ponto de junçãoProjetos colaborativos com várias branches
git rebaseHistórico linear sem pontos de junçãoLimpeza do histórico antes de um merge partilhado

Em resumo:

plaintext
git merge   ->  Histórico completo com commit de fusão
git rebase  ->  Histórico linear sem commit de fusão

Este guia permite-lhe compreender e visualizar as diferenças entre git merge e git rebase, e escolher o método mais adequado em função do contexto do projeto.