Pular para o conteúdo
Cursos

DevClub

LógicaFront-endBack-endMobile

IA Club

IA na prática
Estudar programaçãoEstudar IA
LiçãoIniciantecódigo testado

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.

Rodolfo Mori4 min de leitura

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:

bash
git --no-pager log --oneline --all -3
570f547 feat: adiciona frete expresso f6188e3 fix: atualiza frete padrão e46c466 feat: calcula frete

Fast-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:

bash
git merge --ff-only feat/frete-expresso
Updating e46c466..570f547 Fast-forward precos.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)

--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.

bash
git merge --no-ff feat/frete-expresso -m "merge: integra frete expresso"
Merge made by the 'ort' strategy. precos.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)

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:

bash
git merge feat/frete-expresso
Auto-merging precos.js CONFLICT (content): Merge conflict in precos.js Automatic merge failed; fix conflicts and then commit the result.

O 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:

bash
sed -n '1,20p' precos.js
<<<<<<< HEAD export const frete = 15; ======= export const frete = 18; >>>>>>> feat/frete-expresso

Acima 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:

bash
git status --short
git status | sed -n '1,12p'
UU precos.js On branch main You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge)

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:

js
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:

bash
git add precos.js
git commit -m "merge: concilia modalidades de frete"
[main a8176fb] merge: concilia modalidades de frete

O grafo prova os dois pais:

bash
git --no-pager log --oneline --graph --decorate --all -5
* a8176fb (HEAD -> main) merge: concilia modalidades de frete |\ | * 570f547 (feat/frete-expresso) feat: adiciona frete expresso * | f6188e3 fix: atualiza frete padrão |/ * e46c466 feat: calcula frete

O 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:

bash
git merge --abort
git --no-pager log -1 --oneline
f6188e3 fix: atualiza frete padrão

No 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.

  • git
  • merge
  • conflito
  • branch

Perguntas frequentes

Conflito significa que alguém escreveu código errado?
Não. Significa que o Git encontrou mudanças incompatíveis na mesma região e não possui regra de negócio para escolher. A equipe precisa decidir o resultado correto.

Dúvidas e comentários

Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.

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

  1. Git — git merge — git-scm.com
  2. Pro Git — Basic Branching and Merging — git-scm.com

Continue por aqui