git merge: juntar branches e resolver conflito na mão
Fast-forward, merge commit e o conflito de verdade: como ler os marcadores, resolver no editor, testar e concluir — ou abortar sem estragar o histórico.
git merge integra o histórico de outra branch na branch atual. Quando uma
linha é ancestral direta da outra, o Git faz fast-forward. Quando as duas
avançaram, pode criar um commit com dois pais. Se ambas mudaram a mesma região,
ele para e entrega a decisão para você.
O laboratório parte de precos.js com uma tarifa e duas branches que alteram
a mesma linha. Antes do conflito, a base era:
git --no-pager log --oneline --all -3Fast-forward apenas move a referência
Se main está em e46c466 e a feature tem um commit descendente, não existe
divergência. O merge pode avançar main para o mesmo commit:
git merge --ff-only feat/frete-expresso--ff-only transforma a expectativa em regra: se for necessário um commit de
merge, o comando recusa. Nenhum commit novo nasce; apenas o nome main muda de
endereço.
Um merge commit tem dois pais
Quando main e feature avançam, nenhum ponteiro pode simplesmente alcançar o
outro sem preservar a bifurcação. Um merge bem-sucedido cria um commit cujo
primeiro pai é a branch atual e o segundo é a branch integrada. Alguns times
usam --no-ff para manter a presença da tarefa mesmo quando o avanço direto
seria possível.
git merge --no-ff feat/frete-expresso -m "merge: integra frete expresso"Não há política universal. Um commit de merge preserva a topologia; um fast-forward reduz nós; squash produz um único commit sem os pais da branch. O artigo sobre pull request compara o histórico que cada escolha deixa.
O conflito é uma recusa consciente
No cenário real, main mudou o frete para 15 e a feature para 18. Ao tentar
integrar:
git merge feat/frete-expressoO Git conhece texto e ancestralidade, não sabe se 15 ou 18 é o preço correto. Escolher automaticamente seria inventar uma regra do produto. Por isso ele mantém o merge em andamento e marca o arquivo.
Leia os três marcadores como base de decisão
O arquivo ficou exatamente assim:
sed -n '1,20p' precos.jsAcima de ======= está a versão da branch atual, identificada por HEAD.
Abaixo está a outra branch. Os marcadores não fazem parte de JavaScript válido;
o teste falha até você remover todos e escrever o estado desejado.
Status mantém o roteiro no meio do merge
Antes de editar, o status curto marca UU, modificado nos dois lados:
git status --short
git status | sed -n '1,12p'Unmerged paths: both modified: precos.js
Não dê git add antes de resolver. Add nesse contexto significa “aceito o
conteúdo atual como resolução”, não “marcar conflito para depois”.
Resolva o produto, teste e só então conclua
O resultado decidiu manter duas modalidades:
export const fretePadrao = 15;
export const freteExpresso = 18;O arquivo validado não continha marcadores de conflito e preservava as duas tarifas. Essa é a condição que precisa ser confirmada antes do novo commit.
Depois de rodar os testes do projeto, prepare e conclua:
git add precos.js
git commit -m "merge: concilia modalidades de frete"O grafo prova os dois pais:
git --no-pager log --oneline --graph --decorate --all -5O teste do projeto vem antes do commit porque um arquivo sem marcadores ainda pode conter uma regra errada. Procure também marcadores remanescentes com a ferramenta de busca do editor. A resolução é uma nova mudança e merece a mesma revisão que qualquer código.
Abort devolve o estado anterior
Se você iniciou o merge na branch errada ou ainda não pode decidir, aborte em vez de apagar marcadores manualmente:
git merge --abort
git --no-pager log -1 --onelineNo teste, o status ficou limpo e main voltou à ponta anterior. Alterações
pré-existentes podem tornar a recuperação mais delicada; comece merges com
working tree limpa.
Arquivos gerados, como lockfiles, merecem cuidado. Não escolha “o nosso” ou “o deles” sem entender. Resolva manifestos, reinstale com a ferramenta oficial e gere o lockfile novamente quando o ecossistema permitir. O resultado precisa ser reproduzível.
Outro cuidado é a direção. Estando em main, git merge feat/frete-expresso
integra a feature em main; estando na feature, o mesmo formato com main
atualiza a tarefa com a base. O conjunto de commits pode parecer parecido, mas
o primeiro pai e a branch que avança mudam. Confira git branch --show-current
antes de executar. Em repositório de time, respeite a política de proteção: a
integração final pode precisar acontecer pelo pull request, depois de revisão e
CI, mesmo que o merge local seja tecnicamente possível.
Sua missão é provocar o conflito em um diretório descartável, explicar cada marcador, preservar duas intenções e desenhar o grafo final. Use branches e switch para preparar as linhas e stash apenas se a working tree já contiver uma tarefa que não pertence ao merge. O sucesso é explicar por que o Git parou e qual regra de negócio justificou sua resolução.
Perguntas frequentes
Conflito significa que alguém escreveu código errado?
Dúvidas e comentários
Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.
Entrar para perguntarÉ o mesmo login gratuito dos cursos.
Nenhuma dúvida por aqui ainda — a primeira pode ser a sua.
Todo o código deste artigo foi executado em git version 2.54.0 (Apple Git-156) no macOS 27, e as saídas exibidas são as reais — como produzimos este conteúdo.
Fontes consultadas
- Git — git merge — git-scm.com
- Pro Git — Basic Branching and Merging — git-scm.com


