Como resolver conflitos de merge sem pânico
Conflito de merge não é erro: é o Git pedindo uma decisão sua. Entenda os marcadores, siga o fluxo calmo e aprenda a abortar quando precisar recomeçar.
Você dá um git merge ou um git pull e o terminal devolve aquela mensagem temida: "Automatic merge failed; fix conflicts and then commit the result." O coração acelera, a tentação de fechar tudo e fingir que não aconteceu é real. Calma. Um merge conflict não é um erro do Git, não é sinal de que você quebrou alguma coisa e não significa que seu código está corrompido. É exatamente o contrário: o Git está sendo honesto com você. Ele juntou tudo o que conseguiu juntar sozinho e parou nos pontos onde dois lados mudaram a mesma região do mesmo arquivo, porque essa decisão não é dele — é sua.
Este guia mostra o fluxo calmo para resolver conflitos: entender por que acontecem, ler os marcadores, decidir com intenção, limpar e seguir em frente. Sem pânico, sem comandos mágicos copiados de fórum.
Por que conflitos acontecem (e por que não são erro)
O Git consegue fazer merge automático na esmagadora maioria dos casos. Se você mexeu no arquivo A e seu colega mexeu no arquivo B, não há o que decidir: as duas mudanças entram. Se vocês mexeram no mesmo arquivo, mas em trechos distantes, o Git ainda costuma resolver sozinho, alinhando as alterações por contexto.
O conflito aparece num cenário específico: dois lados editaram a mesma região de linhas, de formas diferentes, e o Git não tem como saber qual versão você quer. Talvez você tenha renomeado uma função e o colega tenha mudado o corpo dela. Talvez os dois tenham ajustado a mesma linha de configuração. O Git poderia escolher um lado arbitrariamente, mas isso seria perigoso — ele engoliria silenciosamente o trabalho de alguém. Em vez disso, ele para e pede uma decisão humana.
É por isso que conflito é decisão de design, não acidente. A pergunta nunca é "qual lado dá menos trabalho para aceitar". A pergunta é "o que cada lado estava tentando fazer, e como o resultado final deve se comportar". Quem resolve conflito escolhendo o caminho preguiçoso costuma reintroduzir bugs que já tinham sido corrigidos ou apagar features inteiras sem perceber.
A anatomia dos marcadores
Quando há conflito, o Git reescreve o arquivo afetado inserindo marcadores ao redor do trecho disputado. Eles parecem assustadores na primeira vez, mas a estrutura é simples:
<<<<<<< HEAD
const timeout = 3000;
=======
const timeout = 5000;
>>>>>>> feature/aumentar-timeout
A leitura é direta. Tudo entre <<<<<<< HEAD e ======= é o seu lado — o estado atual da branch onde você está (o HEAD). Tudo entre ======= e >>>>>>> é o lado que está entrando — as mudanças da branch que você está trazendo, identificada pelo nome ao lado dos sinais de maior. O ======= é apenas a fronteira entre os dois.
Repare numa coisa importante: os marcadores não fazem parte do seu código. São anotações temporárias do Git. Resolver o conflito significa, no fim, deixar o arquivo exatamente como ele deve ficar e apagar todas as três linhas de marcador. Se você esquecer uma delas, o arquivo fica com lixo sintático que vai quebrar o build.
Um detalhe que ajuda muito: ative o estilo de conflito que mostra também a base comum.
git config --global merge.conflictstyle zdiff3
Com zdiff3, o Git adiciona um terceiro bloco mostrando como a região estava antes de qualquer um dos lados mexer. Isso muda o jogo, porque você passa a enxergar a intenção de cada lado em vez de só comparar dois resultados finais sem contexto. Saber de onde os dois partiram é o que permite combinar as mudanças corretamente em vez de chutar.
O fluxo calmo, passo a passo
Quando o merge para, a primeira coisa é respirar e olhar o panorama. Não saia abrindo arquivos no escuro.
git status
O git status lista os arquivos em conflito sob "Unmerged paths". Essa é sua lista de tarefas. Em geral são poucos arquivos — raramente o terror que a mensagem inicial sugere.
Abra cada arquivo conflitado e localize os marcadores. Para cada bloco, você tem três decisões possíveis: manter o seu lado, manter o lado que está entrando, ou combinar os dois numa terceira versão que respeita as duas intenções. Na maioria das vezes a resposta certa é combinar — afinal, os dois lados foram escritos por algum motivo.
Antes de decidir num arquivo grande ou denso, vale comparar as duas versões fora do editor para ver com clareza o que cada lado realmente mudou. Colar os dois trechos num comparador de diferenças lado a lado deixa óbvio o que é igual e o que diverge, o que reduz a chance de você apagar uma mudança sem perceber. Depois de entender, você volta ao arquivo, edita o trecho até ele ficar como deve ficar e apaga as linhas <<<<<<<, ======= e >>>>>>>.
Quando o arquivo estiver limpo e correto, marque-o como resolvido:
git add caminho/do/arquivo.js
Repita para cada arquivo da lista. Quando todos estiverem resolvidos e adicionados, conclua a operação. Num merge, basta:
git status # confirme que não sobrou nada em "Unmerged paths"
git commit # o Git já preenche a mensagem de merge
Se o conflito apareceu durante um git rebase ou um git cherry-pick, o comando para seguir é git rebase --continue ou git cherry-pick --continue em vez de git commit. O git status sempre te diz qual é o próximo passo — leia a saída dele em vez de adivinhar.
A saída de emergência: abortar
Às vezes você começa a resolver, percebe que pegou a branch errada, que o merge foi prematuro ou que está perdido demais para confiar no resultado. Não force a barra. Existe uma saída limpa que devolve tudo ao estado anterior, como se o merge nunca tivesse começado:
git merge --abort
O git merge --abort desfaz o merge em andamento e restaura sua working tree ao estado de antes. Para rebase, o equivalente é git rebase --abort. Saber que essa porta existe é metade da tranquilidade — você nunca está preso. Pode abortar, pensar, conversar com quem fez a outra mudança e tentar de novo com calma.
Como evitar que conflitos virem dor de cabeça
Conflito faz parte de trabalhar em time e não dá para eliminá-lo. Mas dá para deixá-lo pequeno e fácil de resolver. Três hábitos fazem quase toda a diferença.
O primeiro é commits pequenos e frequentes. Quanto menor a mudança, menor a superfície de colisão e mais fácil entender cada lado quando o conflito aparece. Um commit gigante que toca trinta arquivos é uma bomba de conflito esperando para explodir.
O segundo é sincronizar cedo. Quanto mais tempo sua branch fica longe da main, mais ela diverge e pior fica o merge no final. Puxar a base com frequência transforma um conflito monstruoso e tardio em vários conflitos minúsculos e gerenciáveis ao longo do caminho.
O terceiro é o menos técnico e o mais subestimado: conversar com o time sobre quem mexe onde. Boa parte dos conflitos dolorosos nasce de duas pessoas refatorando o mesmo módulo sem saber uma da outra. Um alinhamento de trinta segundos no chat evita horas de merge.
Perguntas frequentes
Posso commitar com os marcadores ainda no arquivo?
Nunca faça isso. Os marcadores <<<<<<<, ======= e >>>>>>> não são código válido em nenhuma linguagem — vão quebrar o build, os testes ou a execução. Commitar marcadores é um dos erros mais constrangedores e mais comuns. Antes de qualquer git add, confira que o arquivo está limpo; muitos editores até destacam os marcadores em vermelho para te avisar.
Como sei qual lado é o "meu" e qual é o "deles"?
O bloco entre <<<<<<< HEAD e ======= é o seu lado — o estado da branch em que você está. O bloco entre ======= e >>>>>>> é o que está entrando, e o nome ao lado dos sinais >>>>>>> identifica de qual branch ou commit aquela mudança veio. Num git pull, "o seu lado" é o seu trabalho local e "o deles" é o que veio do remoto.
O que faço se resolver tudo errado?
Se você ainda não fez o commit final, git merge --abort (ou git rebase --abort) devolve tudo ao estado anterior e você recomeça com calma. Se já commitou e percebeu o erro depois, dá para desfazer o commit de merge com os comandos de reescrita de histórico — assunto que cobrimos em git reset, revert e restore. O importante é não entrar em pânico: praticamente nada no Git é irreversível.
O zdiff3 vale a pena mesmo?
Vale muito, e é grátis. Sem ele, você vê só os dois resultados finais e precisa adivinhar a intenção de cada lado. Com merge.conflictstyle=zdiff3, o Git mostra também a base comum — a versão de onde os dois partiram. Isso transforma "qual desses dois eu escolho" em "o que cada um mudou em relação ao original", que é a pergunta certa para combinar as mudanças sem perder nada.
O que levar daqui
Conflito de merge não é acidente nem castigo: é o Git terceirizando para você a única coisa que ele não pode fazer sozinho — entender a intenção por trás de duas mudanças que se cruzam. Trate cada conflito como uma decisão de design, não como um obstáculo para empurrar com a barriga. Leia os dois lados, entenda o que cada um queria, combine quando fizer sentido, e só então limpe os marcadores e siga. Resolver pelo caminho que dá menos trabalho é como você reintroduz bugs e apaga o trabalho dos outros. E, por favor: jamais commite os marcadores.
- 01 Portfólio de desenvolvedor: o que colocar (e o que cortar) Recrutador olha seu portfólio por vinte segundos. Um projeto terminado e no ar vence dez clones de tutorial. O que incluir, o que cortar e por que o README é metade da impressão.
- 02 Como funciona a memória RAM Entenda o que é memória RAM, por que ela é volátil, como difere do disco e do cache, e quando adicionar mais GB realmente resolve o problema.