Um estudo sobre o Git Rebase

Faz um tempo já que eu andava querendo pesquisar e escrever sobre a diferença entre o git push --force e o git push --force-with-lease. Comecei a pesquisar sobre esses dois hoje e também pensei: hmm, por que não fazer uma introdução sobre isso falando também sobre o Git Rebase? Afinal de contas, é um bichinho tão temido, tem tantas lendas sobre ele e eu, pessoalmente, não sabia muita coisa sobre, só sei que tenho que fazer. Por isso decidi juntar a fome com a vontade de comer e fazer um estudo sobre o Git Rebase e trazer aqui, pra compartilhar com todo mundo!

Merge, Squash ou Rebase?

Conceitualmente, o que é o Git Rebase?

De antemão, já adianto que o rebase é um dos métodos de atualização de branch disponíveis no Git, junto com o merge (se tem algum outro, me conta, porque eu não me lembro 😅). Quando você cria uma feature branch, esse lugarzinho especial onde você vai começar a desenvolver uma funcionalidade nova para um sistema, você o faz a partir do último commit de uma branch principal. A característica do rebase, diferente do merge, é que ele vai mudar a base da sua branch de um commit para o outro, fazendo parecer com que você tenha criado a sua feature branch à partir de um outro ponto de partida, mais recente, diferente daquele onde você iniciou o seu trabalho.

Meio confuso, né? Pérai que vou tentar desenhar.

Um Git Rebase em 3 atos

A pessoa que vos fala foi lá e criou um novo branch a partir da branch principal de um projeto. O commit inicial da minha branch, que aqui foi chamada de branch-oli, é o commit wap662, que contém tudo que está na branch principal até agora.

No dia seguinte, o coleguinha veio e fez merge da feature branch dele, a branch-do-colega, na main. Com isso, a main foi atualizada e seu commit mais recente, que servirá de base para as próximas feature branches a serem criadas, é o commit sus0sz. Porém, a minha branch, branch-oli, ficou desatualizada e eu preciso que ela fique em dia com o que está na branch principal. Eu posso fazer isso de duas formas: com o git merge ou com o git rebase. E hoje, eu vou de rebase: ou seja, vou fazer com que a branch-oli tenha o sus0sz como commit base.

Xablau! Nosso código está devidamente atualizado.

Ok, mas quais são as vantagens do Git Rebase?

A vantagem mais prática do Rebase é: você terá um merge mais limpo da sua feature branch na branch principal. Agora, a vantagem poética é a seguinte: os commits da branch principal são majoritariamente compostos de merges de outras branches. E quando esses merges contém títulos descritivos e feitos com amor e carinho, os commits da main branch vão nos contando a história de um sistema. O Rebase ajuda com que essa história fique mais linear e, com isso, faça mais sentido.

E na hora de procurar qual feature branch meteu um bug lá pra dentro do código-base de produção, fica muito mais fácil achar se tivermos um histórico limpinho e organizado de commits.

E como isso é feito?

O Git organiza essa “história” através da criação de novos commits à partir dos que já foram feitos e os aplicando à base (que, no caso, seria a sua feature branch). Por mais que a branch pareça inalterada para nós, ela é composta por commits completamentes diferentes e novos depois do Rebase.

Tipos de Git Rebase

Existem dois tipos de Git Rebase disponíveis para utilizarmos, cada um contendo suas vantagens e desvantagens.

O Git Rebase Standard, que é quando não passamos nenhuma flag junto com o nosso comando de rebase, vai simplesmente pegar todos os novos commits criados em uma branch e vai adicioná-los automaticamente à frente do novo commit base da nossa feature branch. Sem pensar muito, sem preocupações.

Já o Git Rebase Interactive (ou Interativo) acontece quando, junto ao comando de rebase, passamos também a flag -i para o console/terminal. Esse tipo de rebase nos dá a possibilidade de alterar os commits já feitos durante o processo de desenvolvimento, além de também podermos dividí-los, removê-los ou reordená-los.

Com o rebase interativo, podemos, por exemplo, focar no desenvolvimento da feature sem nos preocuparmos com os commits que estamos fazendo: se suas mensagens estão descritivas o suficiente, se estão contando uma história como deve ser… Vamos só fazendo as alterações necessárias e, antes de fazer o merge para a main, podemos arrumar a casa através da flag -i.

Deixe a limpeza para depois!

Principais diferenças entre o Git Merge e o Git Rebase

Antes de mais nada, é importante ressaltar que ambos os comandos resolvem o mesmo problema: a integração de mudanças de código entre branches.

A principal diferença é: o Git Merge vai trazer o novo código de forma independente e integrá-lo através de um único commit dentro da sua feature branch. Ele é uma operação não-destrutiva, logo: não há grande perigo que você faça alguma mudança não desejada na branch em que você está trabalhando.

Porém, o Merge também vai fazer com que a sua branch tenha commits extras, além daqueles que você criou. Caso a main branch seja muito movimentada e você precise fazer vários merges ao longo do desenvolvimento da sua feature, esses commits extras podem acabar poluindo a “história” da sua branch.

Enquanto isso, o Git Rebase vai reescrevendo a história do seu projeto, como já foi explicado lá em cima. O que é bom em termos de clareza e limpeza de histórico, porém também pode ter um ponto negativo: não vai ser possível ver com clareza quando novas mudanças foram adicionadas na feature, o que faz com que não haja tanto contexto dentro da branch como teria caso as atualizações fossem feitas através do Git Merge.

Sobre os forces pushes durante o Git Rebase

Por que precisamos do —force push durante um rebase?

O Git contém uma regra chamada Fast-Forward Rule: basicamente, ele vai rejeitar qualquer commit se o que estiver na branch remota não for um “ancestral” do que está no local. E o Rebase quebra essa regra, visto que ele cria novos commits e muda a base da branch local, por isso precisamos do force push para burlar isso. A flag --force vai ignorar completamente o histórico já existente da feature branch e vai substituí-lo com o que está na sua máquina.

Diferença entre o —force e o —force-with-lease

O --force é força bruta e pronto. Se por um acaso alguém tiver feito algum commit enquanto você fazia o Git Rebase localmente, essa alteração estará perdida para sempre. Porém, isso pode ser ultrapassado com o --force-with-lease, que eu traduzi livremente para forçado com jeitinho: o Git vai recusar a atualização da branch caso seu estado esteja diferente do esperado.

Capricha no force push!

Ou seja, quando usamos o --force-with-lease, o Git vai, primeiro, verificar se a versão remota da sua feature branch é a mesma que você fez o rebase ou se há alguma alteração além dos commits “re-criados”. Caso haja algo além, como alterações commitadas por outro dev, por exemplo, o push será rejeitado. Se não houver nenhuma alteração adicional, será possível burlar a Fast-Forward Rule sem grandes problemas.

Principais comandos relacionados ao Git Rebase

Para fazer o Rebase:

git rebase [-i] nome-da-branch

Observação: a flag -i é opcional e serve para fazer rebases interativos, conforme expliquei a definição lá em cima.

Para continuar com as alterações feitas:

git rebase --continue

Para pular alterações:

git rebase --skip

Force pushes:

git push --force
git push --force-with-lease

📖 Links consultados

📗git rebase – Atlassian Git Tutorial

📘Atualizando um branch com git rebase – Jessica Temporal

📙Git rebase: integrando alterações de uma branch em outra, por Daniela Araújo – BeTrybe Blog

📕Merging vs. Rebasing – Atlassian Git Tutorial

📗Git Force vs Force with Lease, por Mohammad-Ali A’Râbi

📘Essa resposta no Stack Overflow


📜 Posts mais recentes

🎯 A maneira SMART de escrever objetivos

🫂 Terapia em grupo – sobre criação de conteúdo


💌 Recadinhos

Gostou do texto? Tem algo a adicionar? Alguma crítica construtiva? Feedbacks? Sugestões? Pedidos? Fique à vontade para me contatar via email (oli.pmatt@gmail.com), Twitter (@oliviamattiazzo), LinkedIn (/oliviamattiazzo) ou pela caixa de comentários aqui embaixo! Vai ser um prazer conversar contigo! ✨

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.