Merge e rebase

9 min

Índice


1 — Juntar duas branches: a necessidade

Trabalhou numa branch feature, o código está pronto. É preciso agora reintegrá-lo em main. O Git oferece dois mecanismos para isso: a fusão (merge) e o rebasamento (rebase).

Os dois atingem o mesmo objetivo — reunir o trabalho — mas com uma forma de histórico diferente. É todo o desafio desta lição.

MecanismoIdeia numa frase
MergeCria-se um commit que junta as duas branches, mantendo a história tal qual.
RebaseReproduzem-se os commits de uma branch por cima de outra, como se se tivesse começado mais tarde.

Antes de qualquer integração, confirma-se que se tem a última versão:

bash
git switch main
git pull origin main

↑ Voltar ao topo


2 — A fusão (merge)

O comando git merge reúne uma branch noutra. Existem dois casos.

Caso 1 — Fusão rápida (fast-forward): se main não se moveu desde a criação da branch, o Git avança simplesmente o ponteiro. Nenhum commit de fusão é criado.

Caso 2 — Fusão a três branches (three-way merge): se main recebeu novos commits entretanto, o Git cria um commit de fusão que tem dois pais.

bash
# Colocar-se na branch alvo e depois fundir
git switch main
git merge feature/panier

# Forçar um commit de fusão mesmo que o fast-forward seja possível
git merge --no-ff feature/panier
OpçãoEfeito
git merge featureFusão (fast-forward se possível)
git merge --no-ff featureCriar sempre um commit de fusão (fica o rasto da branch)
git merge --abortAnular uma fusão em conflito

O merge preserva a história real: vê-se quando e como as branches se juntaram. É honesto, mas o histórico pode tornar-se denso com muitos commits de fusão.

🔧 Mini-exercício — Quer fundir feature/panier em main forçando a criação de um commit de fusão, mesmo que um fast-forward fosse possível. Escreva o comando.

✅ Ver uma solução

git merge --no-ff feature/panier — o --no-ff guarda um rasto explícito da branch fundida.

↑ Voltar ao topo


3 — O rebasamento (rebase)

O git rebase desloca os commits da sua branch para os reproduzir por cima da ponta de outra branch. Resultado: um histórico linear, como se tivesse começado o trabalho depois dos últimos commits de main.

Antes do rebase:

Depois de git rebase main (os commits B e C são reproduzidos após D):

bash
# Na branch feature, reproduzir por cima de main
git switch feature/panier
git rebase main

# Depois fusão fast-forward limpa em main
git switch main
git merge feature/panier
Vantagem do rebasePrecaução
Histórico linear e legívelReescreve os commits (novos SHA)
Sem commits de fusão parasitasNunca rebasar uma branch já enviada e partilhada
Ideal antes de uma pull requestConflitos a resolver commit a commit

⚠️ Regra de ouro do rebase: nunca rebase commits já publicados e usados por outros. Está a reescrever a história, o que partiria os repositórios deles. O rebase é para o trabalho local não partilhado.

🔧 Mini-exercício — Está na branch feature/panier. Escreva o comando para reproduzir os seus commits por cima da ponta de main (histórico linear).

✅ Ver uma solução

git rebase main (estando de facto em feature/panier).

↑ Voltar ao topo


4 — Resolver os conflitos

Um conflito ocorre quando o Git não consegue decidir automaticamente: duas branches modificaram a mesma linha do mesmo ficheiro. O Git pára e pede-lhe que decida.

O Git insere marcadores de conflito no ficheiro:

text
<<<<<<< HEAD
prix = 10   # versão de main
=======
prix = 12   # versão de feature
>>>>>>> feature/panier

A resolução passo a passo:

  1. Abrir o ficheiro e escolher (ou combinar) a versão correta.
  2. Apagar os marcadores <<<<<<<, =======, >>>>>>>.
  3. Marcar o ficheiro como resolvido com git add.
  4. Terminar a operação.
bash
# Ver os ficheiros em conflito
git status

# Depois da edição manual
git add fichier-en-conflit.py

# Terminar um merge
git commit

# Terminar um rebase
git rebase --continue

# Em caso de pânico: anular tudo
git merge --abort      # ou: git rebase --abort
Ferramenta de ajudaUso
git statusListar os ficheiros em conflito
git diffVer as diferenças conflituosas
git mergetoolLançar uma ferramenta gráfica de resolução
VS CodeBotões Accept Current / Incoming / Both

Um conflito não é um erro: é o Git a dizer-lhe, com honestidade, « não sei qual ficar, a decisão é sua ». Manter a calma e ler os marcadores chega em 99 % dos casos.

🔧 Mini-exercício — Editou o ficheiro app.py para resolver um conflito ocorrido durante um rebase. Que dois comandos terminam a operação?

✅ Ver uma solução
bash
git add app.py
git rebase --continue

(Para um merge, seria git add app.py e depois git commit.)

↑ Voltar ao topo


5 — Merge ou rebase: o que escolher?

Os dois reúnem o trabalho, mas produzem um histórico diferente. A escolha é muitas vezes uma convenção de equipa.

AspetoMergeRebase
HistóricoFiel, ramificadoLinear, limpo
Commit de fusãoSim (se não for fast-forward)Não
Reescreve a históriaNãoSim (novos SHA)
Seguro em branch partilhada✅ Sim❌ Não
Legibilidade do logMais densaMais clara

A prática recomendada mais habitual:

  • Rebase a sua branch local em main antes de abrir uma pull request → histórico limpo.
  • Merge a pull request em main → rasto claro da integração.
bash
# 1. Limpar a branch local antes da PR
git switch feature/x
git rebase main

# 2. Depois da PR aprovada, o GitHub faz o merge

Frase mnemónica: « Rebase em privado, merge em público. » Rebasa-se o que é seu, funde-se o que é partilhado.

↑ Voltar ao topo


6 — Quiz — Merge e rebase

Question 1

O que faz git merge feature a partir de main quando main também tem novos commits?

a) Apaga a branch feature

b) Cria um commit de fusão com dois pais

c) Apaga o histórico

d) Recusa sempre fundir

💡 Ver a solução

Resposta: b) — É uma fusão a três branches: o Git cria um commit de fusão que reúne as duas histórias.


Question 2

Qual é o efeito principal de um git rebase main?

a) Reproduzir os commits da branch por cima de main para um histórico linear

b) Clonar o repositório

c) Apagar main

d) Criar uma salvaguarda remota

💡 Ver a solução

Resposta: a) — O rebase desloca e reproduz os seus commits no cimo de main, produzindo uma história linear.


Question 3

Por que não se deve rebasar uma branch já enviada e partilhada?

a) Porque o GitHub o proíbe

b) Porque isso reescreve os commits e parte os repositórios dos outros

c) Porque o rebase é mais lento

d) Porque apaga main

💡 Ver a solução

Resposta: b) — O rebase cria novos SHA. Se outros já tiverem esses commits, o histórico deles fica incoerente.


Question 4

O que representam os marcadores <<<<<<<, =======, >>>>>>>?

a) Comentários de código

b) Um erro de sintaxe Python

c) As zonas de um conflito a resolver à mão

d) O fim de um ficheiro

💡 Ver a solução

Resposta: c) — São os marcadores de conflito: acima a versão atual (HEAD), abaixo a versão de entrada. Escolhe-se e apagam-se.


Question 5

Como anular com limpeza uma fusão bloqueada por conflitos?

a) git delete

b) git merge --abort

c) git reset --cloud

d) Apagar a pasta .git

💡 Ver a solução

Resposta: b)git merge --abort (ou git rebase --abort) devolve o repositório ao estado anterior à operação.

↑ Voltar ao topo


7 — Prática — Resolver um conflito de fusão

Instrução

Duas branches modificam a mesma linha de um ficheiro config.txt. Reproduza o conflito e depois resolva-o ficando com as duas informações combinadas.

  1. Em main, o ficheiro contém port = 8080.
  2. Uma branch feature/ssl muda esta linha para port = 443.
  3. Entretanto, main muda a mesma linha para port = 9090.
  4. Funda feature/ssl em main, resolva o conflito ficando com port = 443 (HTTPS) e termine.

Correção

bash
# Preparação: criar o conflito
echo "port = 8080" > config.txt
git add config.txt
git commit -m "Configuração inicial"

git switch -c feature/ssl
echo "port = 443" > config.txt
git commit -am "Passagem a HTTPS (porta 443)"

git switch main
echo "port = 9090" > config.txt
git commit -am "Alteração da porta para 9090"

# Tentativa de fusão → conflito
git merge feature/ssl

O Git mostra então:

text
Auto-merging config.txt
CONFLICT (content): Merge conflict in config.txt
Automatic merge failed; fix conflicts and then commit the result.

O ficheiro config.txt contém:

text
<<<<<<< HEAD
port = 9090
=======
port = 443
>>>>>>> feature/ssl

Edita-se para ficar só com o valor correto:

bash
echo "port = 443" > config.txt   # decide-se a favor do HTTPS

git add config.txt
git commit -m "Fusão feature/ssl: conservação da porta 443"

Resultado esperado:

VerificaçãoComandoSaída
Conflito resolvidogit status« nothing to commit, working tree clean »
Conteúdo finalcat config.txtport = 443
Commit de fusãogit log --oneline -1« Fusão feature/ssl: conservação da porta 443 »

Truque: se se enganar a meio do conflito, git merge --abort devolve-lhe o repositório intacto. Não há risco em experimentar.

↑ Voltar ao topo


8 — Síntese

Pontos a reter

  1. Merge e rebase reúnem duas branches, mas produzem um histórico diferente.
  2. Merge preserva a história real; cria um commit de fusão com dois pais (exceto fast-forward).
  3. Rebase reproduz os commits para um histórico linear e limpo.
  4. Regra de ouro: rebase em privado, merge em público — nunca rebasar código partilhado.
  5. Um conflito aparece quando a mesma linha é modificada dos dois lados: edita-se, faz-se add, termina-se.
  6. Boa prática: rebasar a branch antes da PR e depois fazer merge da PR em main.

A continuação

Já sabe integrar o código tecnicamente. A lição 03 — Pull requests mostra como fazer reler este trabalho antes de o integrar, no centro da colaboração no GitHub.

↑ Voltar ao topo


Todos os direitos reservados. Qualquer reprodução, difusão, utilização ou adaptação deste curso, no todo ou em parte, é estritamente proibida sem a autorização escrita prévia do Dr. Haythem REHOUMA.

Curso criado por Dr. Haythem REHOUMA — Desenvolvimento e implementação de soluções de dados