Merge: integrando branches

1. O que é um merge e por que usá-lo?

No Git, um merge (ou mesclagem) é o processo de unificar dois históricos de desenvolvimento separados em um único fluxo. Quando você trabalha com branches — sejam elas para features, correções ou experimentos — chega o momento de integrar essas alterações de volta ao branch principal (geralmente main ou master).

O merge é essencial em cenários como:
- Integrar uma funcionalidade completa ao branch principal
- Atualizar um branch de feature com as últimas alterações do branch principal
- Colaborar em equipe, onde múltiplos desenvolvedores trabalham em paralelo

É importante distinguir merge de rebase. Enquanto o merge preserva o histórico completo, criando um commit especial que une as linhas do tempo, o rebase reescreve o histórico ao aplicar commits de uma branch sobre outra, resultando em um histórico linear. Cada abordagem tem seu lugar, mas o merge é preferido quando se deseja manter a fidelidade cronológica do desenvolvimento.

2. Preparando o ambiente para o merge

Antes de executar um merge, é fundamental verificar o estado atual do repositório. Comece com:

git status
git log --oneline --graph --all

O comando git status mostra se há alterações não commitadas que possam interferir no processo. O git log com as flags --oneline, --graph e --all exibe uma árvore visual dos commits e branches.

Certifique-se de que o branch de destino (por exemplo, main) esteja atualizado com o repositório remoto:

git checkout main
git pull origin main

Em versões modernas do Git (2.23+), você pode usar git switch no lugar de git checkout:

git switch main
git pull origin main

Isso garante que você está partindo do estado mais recente do branch que receberá as alterações.

3. Executando um merge básico

Com o branch de destino ativo e atualizado, o merge é feito com:

git merge <nome-do-branch>

Vamos a um exemplo prático. Suponha que temos um branch feature-login com commits de uma nova funcionalidade de autenticação. Para integrá-la ao main:

git switch main
git merge feature-login

Nos bastidores, o Git analisa os históricos dos dois branches. Se não houver conflitos, ele cria automaticamente um merge commit — um commit especial que tem dois pais: o último commit do branch de destino e o último commit do branch sendo mesclado.

Após o merge, você pode verificar o resultado:

git log --oneline --graph

A saída mostrará o merge commit conectando as duas linhas do tempo.

4. Fast-forward merge: o caso mais simples

O fast-forward merge ocorre quando o branch de destino não teve novos commits desde que o branch de feature foi criado. Nesse caso, o Git simplesmente avança o ponteiro do branch de destino para o commit mais recente do branch de feature, sem criar um commit extra.

Exemplo:

# Situação: main está no commit A, feature-login foi criado a partir de A
# feature-login avançou para B, C, D (main permaneceu em A)
git switch main
git merge feature-login
# Resultado: main agora aponta para D, sem commit de merge

Para forçar a criação de um merge commit mesmo quando o fast-forward é possível, use a flag --no-ff:

git merge --no-ff feature-login

Isso é útil quando você deseja documentar visualmente no histórico que uma branch foi integrada, especialmente em projetos que seguem Git Flow ou convenções similares.

5. Three-way merge: quando os históricos divergem

O three-way merge é necessário quando ambos os branches tiveram commits desde que divergiram. O Git precisa reconciliar três versões de cada arquivo:
- O commit base (ancestral comum de ambos os branches)
- A versão no branch de destino
- A versão no branch de origem

Exemplo de cenário:

# main: A → B → C
# feature-login: A → X → Y (branch criado a partir de A)
# Ambos evoluíram independentemente
git switch main
git merge feature-login

O Git encontra o commit A como base, compara as alterações em C e Y, e tenta combiná-las automaticamente. Se as alterações não conflitarem, um merge commit é criado com dois pais (C e Y).

6. Lidando com conflitos de merge

Quando o Git não consegue mesclar automaticamente trechos de código que foram modificados em ambos os branches, ocorre um conflito de merge. Você identificará isso por:

git status
# Saída indica arquivos com conflitos (both modified)

Dentro dos arquivos conflitantes, você verá marcadores:

<<<<<<< HEAD
versão do branch de destino (main)
=======
versão do branch de origem (feature-login)
>>>>>>> feature-login

Para resolver, edite o arquivo manualmente, escolhendo uma das versões, combinando ambas ou criando uma nova solução. Após editar, remova os marcadores <<<<<<<, ======= e >>>>>>>.

Finalize com:

git add arquivo-resolvido.txt
git commit
# ou, em versões recentes:
git merge --continue

O Git abrirá o editor para você ajustar a mensagem do merge commit.

7. Boas práticas e ferramentas úteis

Algumas práticas recomendadas para evitar dores de cabeça com merges:

  • Mantenha branches pequenas e de curta duração: Quanto mais tempo um branch existir, maior a probabilidade de conflitos complexos.
  • Faça merges frequentes: Atualize seu branch de feature com o branch principal regularmente (git merge main enquanto estiver no branch de feature).
  • Use git merge --abort para desistir: Se um merge estiver problemático, você pode abortá-lo e voltar ao estado anterior.
  • Utilize ferramentas visuais: O comando git mergetool abre ferramentas como Meld, KDiff3 ou Beyond Compare para resolver conflitos de forma mais intuitiva.

Configuração de mergetool:

git config merge.tool kdiff3  # ou meld, vimdiff, etc.
git mergetool

Lembre-se: conflitos não são erros — são oportunidades de revisão e colaboração. Uma boa comunicação com a equipe e commits frequentes reduzem significativamente a complexidade dos merges.

Referências