Executando verificação de segurança...
3

Dominando o Git Rebase

O comando git rebase é frequentemente temido por desenvolvedores, mas quando usado corretamente, pode ser uma ferramenta poderosa para manter um histórico de commits limpo e organizado.

O que é rebase e quando usar

Diferente do merge, que cria um novo commit combinando duas branches, o rebase reescreve o histórico de commits, aplicando-os em uma nova base. Isso resulta em um histórico linear e mais limpo.

Use rebase quando:

  • Quiser manter um histórico de projeto linear
  • Estiver trabalhando em uma branch de feature e precisar atualizar com as mudanças da main
  • Quiser limpar commits antes de mesclar à branch principal

Evite rebase quando:

  • A branch já foi compartilhada publicamente
  • Não entender completamente as implicações

Rebase na prática

Vamos ver um exemplo prático:

# Estando na sua branch de feature
git checkout feature

# Atualizando com as mudanças da main
git rebase main

# Se houver conflitos, resolva-os e continue
git add .
git rebase --continue

Rebase interativo: a ferramenta secreta

O rebase interativo permite reorganizar, combinar e modificar commits:

git rebase -i HEAD~5  # Interagir com os últimos 5 commits

Isso abrirá um editor com opções como:

  • pick: manter o commit
  • squash: combinar com o commit anterior
  • reword: alterar a mensagem
  • drop: remover o commit

Conclusão

O rebase é uma ferramenta poderosa que, quando usada com cuidado, pode transformar seu fluxo de trabalho com Git. A chave é entender quando e como aplicá-lo.

Para mais conteúdo sobre Git em português, confira o Git Pie.

Carregando publicação patrocinada...
1

Pra quem quiser se aprofundar no funcionamento do git rebase, eu recomendo este site.

É longo e no começo parece que não tem nada a ver com rebase, mas eu sugiro que leia com atenção até o final porque vale muito a pena.

Basicamente, é explicado como um repositório do Git é estruturado, pois isso é essencial para entender o que o rebase de fato faz.

Mas só para resumir bastante (pois ainda recomendo que leia o link indicado), vamos supor que meu repositório esteja assim:

Repositório com o branch develop divergindo do main

Ou seja, tenho o branch main, com os commits first, A, B e C.
A partir do commit A foi criado o branch develop, no qual foram adicionados os commits D e E.

Eu quero que o develop contenha as mudanças feitas nos commits B e C. Para isso posso usar merge ou rebase.


Se eu usar merge:

git checkout develop
git merge main

O resultado será:

Repositório após git merge main a partir do develop

Ou seja, o branch develop agora tem um novo commit F, que é o resultado do merge. No caso ele terá dois pais: os commits C e E.


Agora, se eu fizer o rebase:

git checkout develop
git rebase main

O resultado será:

Repositório após git rebase main a partir do develop

Agora o branch develop foi "movido" para a frente do branch main, e os commits D e E foram "re-aplicados" a partir do commit C.

Isso criou dois commits novos (D' e E'), e isso na minha opinião é o detalhe mais importante: as alterações feitas nos commits D e E são aplicadas novamente a partir do commit C, e isso cria dois commits novos. Embora as alterações feitas sejam as mesmas, não são os mesmos commits (pois possuem pais diferentes: o pai de D é o commit A, já o pai de D' é o commit C).

Os próprios hashs dos commits também não serão os mesmos, o que indica que são de fato commits diferentes. Além disso, se o rebase for feito por um usuário diferente de quem criou o branch, os autores também serão diferentes. E no caso, os commits originais (D e E) ficarão "perdidos" e o Git pode inclusive apagá-los automaticamente depois de um tempo.

Enfim, o rebase é como se eu "reescrevesse a história". Para quem vê somente o resultado final, é como se as alterações feitas em D e E sempre tivessem sido feitas a partir de C.

Repare que com isso o histórico fica linear, enquanto que no merge ele se divide em dois caminhos: primeiro diverge em A para depois convergir em F. Mas no fim o resultado final acaba sendo essencialmente o mesmo: o branch develop contém todas as alterações feitas por ele (D' e E') ao mesmo tempo em que também tem o que foi feito em B e C.

O que muda é como isso foi feito. Podemos dizer que o rebase se foca mais no resultado final, sem se importar em como isso aconteceu (tanto que ele reescreve o histórico, pois o "como" é o que menos importa). Já o merge preserva o histórico de como tudo aconteceu ("aqui o código se dividiu, mas depois se juntou lá na frente, etc"). O "como" importa e permanece intocado.

E para mais detalhes, sugiro também este outro artigo.