git merge: como mesclar branches e resolver conflitos
O git merge une o histórico de outra branch com a branch atual: se a branch atual não avançou, o Git apenas move o ponteiro (fast-forward); caso contrário, cria um commit de merge com dois pais. Vá para a branch de destino e execute git merge nome-da-branch; em caso de conflito, corrija os arquivos, rode git add e git commit, ou cancele tudo com git merge --abort.
O que o git merge faz
O comando git merge pega as alterações da branch indicada e as incorpora à branch em que você está agora. É importante guardar a direção: o merge é feito "para dentro de si". Para levar feature/login para a main, primeiro se muda para a main e depois se chama o merge.
git switch main
git pull # trazer a main atualizada do servidor
git merge feature/login
O Git não copia nada linha a linha "à mão". Ele encontra o ancestral comum das duas branches (merge base), compara as duas versões com ele e soma as alterações. Se cada lado mexeu em lugares diferentes, o resultado sai automaticamente. Se mexeram no mesmo lugar, surge um conflito, e quem decide é você.
Dois modos: fast-forward e merge de três vias
Fast-forward — quando não é preciso commit de merge
Suponha que você criou feature a partir da main, fez três commits e, nesse meio-tempo, ninguém adicionou nada à main. Então o histórico da main é só o começo do histórico da feature. O Git move o ponteiro da main para a frente, até o último commit da feature, e nenhum commit novo é criado.
$ git merge feature
Updating 3f2a1c4..9b7e0d2
Fast-forward
src/auth.js | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
O histórico continua linear, mas o fato de que "aqui existia a branch feature" se perde. Às vezes isso é bom, às vezes não — veja mais abaixo, na seção sobre --no-ff.
Merge de três vias e commit de merge
Se as duas branches avançaram a partir do ancestral comum, já não dá para só mover o ponteiro. O Git faz um merge de três vias: a base, o "nosso" lado (branch atual) e o "deles" (branch mesclada). O resultado é registrado num commit de merge separado, que tem dois pais.
$ git merge feature
Merge made by the 'ort' strategy.
src/auth.js | 42 ++++++++++++++++++++
src/router.js | 3 +-
2 files changed, 44 insertions(+), 1 deletion(-)
O Git abre o editor com uma mensagem como Merge branch 'feature'. Você pode deixá-la como está ou explicar por que o merge foi feito. Para ver a "bifurcação" resultante, use:
git log --oneline --graph --all
A estratégia ort é a padrão desde o Git 2.34; antes era a recursive. No trabalho do dia a dia, não é preciso trocar de estratégia.
Flags úteis do git merge
| Flag | O que faz | Quando é útil |
|---|---|---|
--no-ff | Sempre cria um commit de merge, mesmo quando um fast-forward é possível | Você quer ver no histórico quais commits vieram de uma mesma feature |
--ff-only | Mescla só por avanço rápido; caso contrário, termina com erro | Atualizar uma branch local sem commits de merge acidentais |
--squash | Coloca todas as alterações da branch no índice, mas não faz commit nem cria vínculo com a branch | É preciso transformar a feature em um único commit organizado |
--no-commit | Faz o merge, mas para antes do commit | Você quer conferir o resultado ou rodar os testes antes de registrar |
-m "texto" | Define a mensagem do commit de merge | Merge em scripts e sem editor |
--abort | Cancela o merge iniciado e volta ao estado anterior | Conflitos demais, é melhor recomeçar |
--continue | Conclui o merge depois de resolver os conflitos | Alternativa ao git commit no último passo |
-X ours / -X theirs | Nos trechos em conflito, escolhe automaticamente a nossa versão ou a deles | Você sabe de antemão qual versão é a certa (cuidado!) |
--no-ff: preservar os limites da feature
Muitos times só mesclam features com --no-ff. Assim, no grafo, cada tarefa aparece como uma "bolha" e pode ser revertida com um único git revert -m 1 <commit-de-merge>. Com fast-forward esse ponto não existe, e seria preciso desfazer cada commit separadamente.
--squash: um commit em vez de dez
git switch main
git merge --squash feature/login
git commit -m "Login por e-mail e senha"
Depois de um --squash, o Git não considera a branch mesclada: git branch -d feature/login se recusa a apagá-la, com o aviso "not fully merged". Apague com git branch -D quando tiver certeza de que está tudo no lugar. E não continue trabalhando na mesma branch depois do squash — o próximo merge vai trazer de novo alterações já integradas e quase certamente gerar conflitos.
Conflito de merge: como resolver
Conflito é uma situação normal de trabalho, não um desastre. Significa apenas que duas branches alteraram as mesmas linhas (ou uma apagou um arquivo que a outra editou), e o Git não vai adivinhar qual versão está certa.
$ git merge feature/login
Auto-merging src/config.js
CONFLICT (content): Merge conflict in src/config.js
Automatic merge failed; fix conflicts and then commit the result.
Passo 1. Ver o que está em conflito
$ git status
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: src/config.js
Passo 2. Editar o arquivo
No arquivo em conflito, o Git coloca marcadores:
<<<<<<< HEAD
const TIMEOUT = 5000;
=======
const TIMEOUT = 10000;
>>>>>>> feature/login
A parte de cima é a sua branch atual (HEAD); a de baixo, a branch que está sendo mesclada. Deixe a versão correta (ou combine as duas), apague as três linhas de marcador e salve o arquivo. Um erro comum é esquecer um marcador no meio do arquivo; antes do commit, procure por eles: o git diff --check destaca os marcadores que sobraram.
Passo 3. Marcar a resolução e concluir o merge
git add src/config.js
git commit # ou git merge --continue
Se o conflito se resolve inteiro escolhendo um dos lados, não é preciso editar o arquivo à mão:
git checkout --ours src/config.js # manter a versão da branch atual
git checkout --theirs src/config.js # pegar a versão da branch mesclada
git add src/config.js
Mais fácil no editor
O VS Code, as IDEs da JetBrains e outros editores mostram o conflito em três colunas e oferecem botões como "aceitar atual / recebida / ambas". Também dá para ligar uma ferramenta externa com git mergetool. Uma configuração útil é git config --global merge.conflictStyle zdiff3: os marcadores passam a mostrar também a versão original do ancestral comum, e fica claro quem mudou o quê.
Mudou de ideia — cancelar o merge
git merge --abort
O comando devolve a pasta de trabalho e o índice ao estado anterior ao git merge. Por isso, antes de um merge é melhor ter a árvore de trabalho limpa: faça commit das alterações inacabadas ou guarde-as com git stash, senão vai ser difícil separá-las do resultado do merge.
Como desfazer um merge já feito
Se o commit de merge ainda não foi enviado ao servidor, o mais simples é voltar a branch:
git reset --hard ORIG_HEAD
O Git grava o ORIG_HEAD antes de operações perigosas, incluindo o merge — é a posição da branch antes dele. O --hard descarta alterações não commitadas, então confira o git status.
Se o merge já está no repositório compartilhado, o histórico não é reescrito. Cria-se um commit inverso:
git revert -m 1 a1b2c3d
A flag -m 1 indica que o pai "principal" é o primeiro (a branch que recebeu o merge). Cuidado com a pegadinha: depois desse revert, o Git considera os commits da feature como já integrados. Se mais tarde você quiser mesclar a feature corrigida de novo, primeiro terá de fazer o revert do próprio commit de revert.
Merge no trabalho em equipe
git pull é fetch mais merge
O git pull comum baixa as alterações e mescla a branch remota na local. Se você e um colega fizeram commits em paralelo, aparece um commit "Merge branch 'main' of ...". Para evitar esses merges técnicos, configure git config --global pull.ff only (o pull falha se o avanço rápido não for possível, e você decide o que fazer) ou use git pull --rebase.
Pull request e o botão Merge
No GitHub e no GitLab, o merge normalmente acontece por um pull/merge request. O botão "Create a merge commit" equivale a git merge --no-ff, "Squash and merge" a um merge com compactação, e "Rebase and merge" a um rebase. A escolha do modo é um acordo do time; o mecanismo é o mesmo do terminal.
Trazer a main para a sua branch
Uma branch de longa duração se afasta da main, e os conflitos se acumulam. Traga a branch principal para a sua regularmente:
git switch feature/login
git fetch origin
git merge origin/main
Assim os conflitos são resolvidos em porções pequenas, conforme aparecem, e o merge final na main corre sem sustos.
Erros comuns
- Merge na direção errada. Rodou
git merge mainestando namainou mesclou uma feature em outra feature. Confira a branch atual comgit branch --show-currentantes do merge. - Merge com uma branch desatualizada. Mesclou a
mainlocal, que não era atualizada havia uma semana. Primeirogit pull, depois o merge. - "Your local changes would be overwritten by merge". A pasta de trabalho tem alterações não commitadas nos mesmos arquivos. Faça commit delas ou guarde-as no stash.
- "refusing to merge unrelated histories". As branches não têm ancestral comum — por exemplo, o repositório local foi criado com
git inite o remoto já tem um README. Se a união for mesmo necessária, adicione--allow-unrelated-histories. - Commitou os marcadores de conflito. O build quebra no
<<<<<<<. Confira comgit diff --checke rode os testes antes do commit.
Resumo
O git merge é uma forma segura de unir branches: ele não reescreve os commits existentes, apenas adiciona um novo (ou avança o ponteiro). Faça o merge na branch atual, mantenha a árvore de trabalho limpa, use --no-ff se os limites das features importam e --squash se precisar de um único commit. Conflitos se resolvem em três passos — editar o arquivo, git add, git commit — e o git merge --abort sempre leva você de volta ao ponto de partida. O merge de branches e a resolução de conflitos são treinados em detalhe na prática no curso de Git.
Perguntas frequentes
Qual a diferença entre git merge e git pull?
O git pull primeiro baixa as alterações do servidor (git fetch) e depois mescla a branch remota na atual com git merge ou, se configurado, com rebase. O git merge trabalha só com o que já existe localmente.
Dá para mesclar várias branches de uma vez?
Sim, git merge feature-a feature-b faz um merge octopus, com vários pais, mas só se não houver conflitos. Na prática, as branches costumam ser mescladas uma de cada vez.
Como ver quais branches já foram mescladas na atual?
O comando git branch --merged mostra as branches totalmente incorporadas à atual, e git branch --no-merged as que ainda não foram. As branches mescladas podem ser apagadas tranquilamente com git branch -d.
Como ver antes o que o merge vai trazer?
Execute git log main..feature para ver os commits que não estão na main, e git diff main...feature para ver as alterações da branch em relação ao ancestral comum.
O que é o ORIG_HEAD depois de um merge?
É uma referência que o Git salva antes do merge: ela aponta para a posição da branch antes dele. Com git reset --hard ORIG_HEAD você desfaz um merge local enquanto ele ainda não foi enviado ao servidor.
Este tema é abordado em profundidade, com prática, no curso “Git do zero ao desenvolvedor confiante”.
Ir para o curso