O controle de versão com o Git tornou-se padrão em todo o cinturão de ferramentas de qualquer desenvolvedor moderno. Comandos como commit
, push
e pull
fizeram parte da memória muscular dos nossos dedos. Mas relativamente poucos desenvolvedores conhecem os recursos “mais avançados” do Git — e quão incrivelmente valiosos eles podem ser! Neste artigo, exploraremos o “rebase interativo”, uma das ferramentas mais poderosas do Git.
Por que o Rebase Interativo deve fazer parte do kit de ferramentas de todo desenvolvedor
Resumindo, e sem exagero, o rebase interativo pode ajudar você a se tornar um desenvolvedor melhor, permitindo que você crie um histórico de commits limpo e bem estruturado em seus projetos.
Por que um histórico de commits bem estruturado é importante? Imagine o oposto: um histórico de commits difícil de ler, onde você não tem ideia do que seus colegas realmente fizeram com suas recentes alterações. Cada vez mais “cantos escuros” começam a surgir em tal projeto, e você só entende as pequenas partes em que trabalhou.
Compare isso com um histórico de commits limpo e bem estruturado: isso ajuda a tornar o código-fonte de um projeto mais legível e mais fácil de entender. Esta é uma peça fundamental para um projeto saudável e duradouro!
O que o Rebase Interativo pode fazer por você
O Rebase Interativo ajuda você a otimizar e limpar seu histórico de commits. Ele abrange muitos casos de uso diferentes, alguns dos quais permitem que você faça o seguinte:
- editar uma mensagem de commit antiga
- excluir um commit
- comprimir/combinar vários commits
- reordenar commits
- corrigir commits antigos
- dividir/reabrir commits antigos para edição
Quando Usar Rebase Interativo (E Quando Não Usar!)
Como algumas outras ferramentas do Git, o rebase interativo “reescreve a história”. Isso significa que, ao manipular uma série de commits usando rebase interativo, essa parte de sua história de commit será reescrita: os hashes SHA-1 dos commits terão mudado. São objetos de commit completamente novos, por assim dizer.
Esse fato exige uma regra simples, mas importante a ser seguida: não use rebase interativo (ou outras ferramentas que reescrevem a história) em commits que você já compartilhou com seus colegas em um repositório remoto. Em vez disso, use-o para limpar seus próprios commits locais — como em uma de suas próprias branches de recurso — antes de mesclá-los em uma branch de equipe.
O Mecanismo Básico de uma Operação de Rebase Interativo
Embora existam muitas coisas diferentes que o rebase interativo possa ser usado, o fluxo de trabalho básico é sempre o mesmo. Uma vez que você entendeu firmemente esse mecanismo básico, o rebase interativo perderá seu ar de “mistério complexo” e se tornará um item valioso e acessível em seu cinturão de ferramentas.
Passo 1: Onde você deve iniciar a sessão?
A primeira pergunta que você precisa responder é: “Que parte da minha história de commit eu quero manipular?” Isso indica onde você deve iniciar sua sessão de rebase interativo. Vamos fazer um exemplo prático e dizer que gostaríamos de editar uma mensagem de commit antiga (que é o que realmente faremos na prática em um momento).
A situação inicial é mostrada abaixo, onde estamos editando uma mensagem de commit antiga via rebase interativo.
Para poder alterar a mensagem de commit em C2
, temos que iniciar nossa sessão de rebase interativo no commit pai dele (ou mesmo antes disso, se desejar). Neste caso de exemplo, usaríamos C1
como ponto de partida para nossa sessão de rebase interativo.
Passo 2: iniciando a sessão real!
Iniciar a sessão real é bastante simples:
$ git rebase -i HEAD~3
Estamos usando o comando git rebase
com a bandeira -i
(para indicar que realmente queremos que seja “interativo”) e fornecemos o commit base (que elaboramos no primeiro passo acima). Neste exemplo, usei HEAD~3
para especificar o commit que está “3 atrás do commit HEAD”. Alternativamente, também poderia ter fornecido um hash SHA-1 específico.
Passo 3: dizendo ao Git o que você deseja fazer
Após iniciar a sessão de rebase interativo, você será apresentado a uma janela de editor onde o Git lista uma série de commits — desde o último commit até (mas não incluindo) o que você escolheu como commit base no Passo 1.
Há duas coisas importantes a ter em mente neste passo:
- Os commits são listados em ordem reversa! O commit mais recente, que esperaríamos aparecer no topo, aparecerá no fundo da lista. Não se preocupe: seu repositório Git está em plena forma! 🥳 Lembre-se de que estamos no processo de realizar uma operação de rebase interativo, e isso requer que o Git reaplique os commits de mais antigos para os mais recentes no final da operação.
- Não faça suas mudanças reais nesta janela de editor! Embora você possa estar com vontade de simplesmente ir em frente e alterar a mensagem de commit nesta janela de editor (afinal, é isso que realmente queremos fazer…), você precisa ter paciência. Aqui, apenas vamos dizer ao Git o que queremos fazer — mas não faremos a mudança real. Vou demonstrar isso em prática em breve!
Agora que esta visão teórica está fora do caminho, vamos mergulhar em alguns casos práticos juntos!
Editando uma Mensagem de Commit Antiga
Um dos casos de uso muito populares de rebase interativo é que você pode editar uma mensagem de commit antiga após o fato. Você pode estar ciente de que git commit --amend
também permite que você altere a mensagem de um commit — mas apenas se for o último commit. Para qualquer commit mais antigo que isso, temos que usar o rebase interativo!
Vamos ver um cenário concreto. Abaixo está uma imagem de uma mensagem de commit ruim que precisa ser corrigida.
Nota: Para uma melhor visualização e visualização mais clara, estou usando o Tower Git desktop client em algumas de minhas capturas de tela. Você não precisa do Tower para acompanhar este tutorial.
Para o nosso exemplo, digamos que gostaríamos de editar a mensagem do commit atualmente intitulado “Otimizar a estrutura do marcador no índice…”
Nosso primeiro passo é determinar o commit base para iniciar esta sessão de rebase interativa. Como temos que (pelo menos) voltar ao pai do nosso commit “maçã podre”, estamos começando nossa sessão em HEAD~3 (três commits atrás do commit HEAD, que é o que tem o título “Alterar títulos…”):
$ git rebase -i HEAD~3
Logo após executar este comando, o seu editor favorito abrirá e apresentará a lista de commits que você acabou de selecionar (fornecendo um commit base).
Lembrando: embora você possa estar tentado a fazê-lo, não mudamos a mensagem do commit aqui. Apenas marcamos a linha respectiva com um “palavra-chave de ação”. Neste caso, queremos reword
o commit (o que significa que gostaríamos de alterar a mensagem do commit, mas deixar o resto do commit como está).
Praticamente, todas as palavras-chave de ação disponíveis são documentadas na parte inferior desta janela – então não há necessidade de lembrar de nada de cor!
Depois de substituir a palavra-chave padrão pick
(que significa “tomar o commit como está”) com a sua palavra-chave de ação preferida, você pode simplesmente salvar e fechar a janela.
Após fazer isso, uma nova janela de editor abrirá contendo a mensagem de commit atual. Finalmente, podemos fazer o que pretendíamos fazer desde o início: editar a mensagem deste antigo commit!
Após fazer nossa alteração e depois salvar e fechar a janela do editor, a sessão de rebase interativa está completa – e a nossa mensagem de commit está atualizada! 🎉
Excluindo um Commit Indesejado
O rebase interativo também permite que você delete um commit antigo de seu histórico que você não precisa (ou quer) mais. Imagine que você incluiu acidentalmente uma senha pessoal em um commit recente: informações sensíveis como essa não devem, na maioria dos casos, ser incluídas em um código fonte.
Lembre-se também de que simplesmente deletar a informação e fazer um novo commit não resolve realmente o seu problema: isso significaria que a senha ainda está salva no repositório, na forma do seu antigo commit. O que você realmente deseja é limpar e completamente delete essa peça de dados do repositório inteiramente!
Vamos começar determinando o commit base para nossa sessão de rebase interativo. Como precisamos começar pelo menos no pai do commit ruim, estamos usando o commit “Optimize markup structure…” como nosso ponto de partida:
$ git rebase -i 6bcf266b
Observe que, desta vez, usei um hash SHA-1 concreto no comando git rebase -i
. Em vez do hash do commit, é claro, poderia ter usado HEAD~2
para referir-se a esse commit.
Após executar este comando, somos apresentados novamente com uma lista de commits.
Desta vez, estamos usando a palavra-chave de ação drop
para se livrar do commit indesejado. Alternativamente, neste caso especial, também poderíamos simplesmente deletar a linha inteira do editor. Se uma linha (representando um commit) não estiver mais presente ao salvar e fechar a janela, o Git deletará o commit respectivo.
No entanto você escolha fazê-lo, após salvar e fechar a janela do editor, o commit será deletado do histórico do seu repositório!
Combinando Múltiplos Commits em Um
Outro caso de uso para o rebase interativo é quando você deseja combinar vários commits separados em um único. Antes de mergulharmos em como isso funciona, vamos dedicar alguns momentos para discutir quando ou por que isso pode ser valioso.
Em geral, fazer com que os commits sejam “maiores” (combinando vários em um) não é uma boa estratégia na maioria dos casos. A regra geral é manter os commits o menor possível, porque “pequeno” significa “mais fácil de ler e entender”. Mas há situações em que isso pode fazer sentido. Aqui estão dois exemplos:
- Imagine que você percebeu um problema com um commit mais antigo. Você pode então prosseguir e produzir um novo commit que fixa o problema. Nessa situação, ser capaz de combinar esses commits em um único faz muito sentido: o commit mais recente, afinal, era apenas um “curativo” para corrigir um problema que não deveria estar lá em primeiro lugar. Ao combinar esses commits, parece que nunca houve um problema!
- Outro exemplo é quando você percebe que fez as coisas um pouco demais granulares. Fazer commits pequenos é ótimo, mas poluir seu histórico de commits com muitos pequenos desnecessariamente significaria exagerar.
A justificativa é a mesma nos dois exemplos: ao combinar dois (ou vários) commits que deveriam ter sido um único desde o início, você está produzindo um histórico de commits mais limpo e legível!
Vamos passar por um exemplo prático juntos e considerar a situação retratada abaixo como nosso ponto de partida.
Vamos supor que, semanticamente, faz mais sentido que esses dois commits sejam um único. Usando a ferramenta squash
do rebase interativo, podemos de fato combiná-los:
$ git rebase -i HEAD~3
Até agora, você já está acostumado com o que acontece a seguir: uma janela de editor abre com uma lista de commits.
I already mentioned that we’re going to use the squash
action keyword in this case. There’s an important thing to know about how squash
works: the line you mark up with the keyword will be combined with the line directly above! This explains why I marked line 2 with the squash
keyword in our example.
Após salvar e fechar essa janela, outra será aberta. Isso porque, ao combinar vários commits, estamos, é claro, criando um novo. E este precisa de uma mensagem de commit, como qualquer outro commit também!
O que você vê na captura de tela acima é o que o Git preparou para nós: combinou as mensagens de commit das respectivas commits originais junto com alguns comentários. Você é livre para deletar as mensagens antigas e começar do zero — ou mantê-las e adicionar mais algumas informações.
Após salvar e fechar essa janela de editor, podemos afirmar com orgulho: o que costumava ser dois commits separados agora é um único!
Aproveitando o Poder do Rebase Interativo
I hope you agree that Git’s interactive rebase tools can be very valuable! As developers, it’s important for us to strive for a clean and clear commit history. It’s a crucial ingredient in keeping a codebase healthy and easy to understand (both for your teammates, and yourself, after some time has passed).
Se você deseja aprender mais, recomendo fortemente o “Kit de Primeiros Socorros para Git”. É uma coleção (gratuita) de vídeos curtos que mostram como limpar e desfazer erros no Git.
Divirta-se!
Perguntas Frequentes (FAQs) sobre Rebase Interativo do Git
Qual é a diferença entre Git Rebase e Git Merge?
O Git Rebase e o Git Merge são duas maneiras diferentes de integrar alterações de uma branch em outra. O Git Merge é uma forma direta de combinar código de duas branches diferentes. Ele cria um novo commit na história, preservando a ordem cronológica dos commits. Por outro lado, o Git Rebase é uma maneira de mover ou combinar uma sequência de commits para um novo commit base. É como dizer “Eu quero basear minhas alterações no que todo mundo fez”. Em outras palavras, ele permite que você coloque as alterações da branch atual em cima de outra branch.
Como posso desfazer um Git Rebase?
Se você deseja desfazer um Git Rebase, pode usar o comando git reflog
para encontrar o commit que deseja retornar, e então usar o comando git reset --hard HEAD@{number}
. O comando git reflog
mostra uma lista de todas as mudanças feitas no HEAD, e o comando git reset
permite que você defina o HEAD atual para o estado especificado.
Qual é o propósito do Git Interactive Rebase?
O Git Interactive Rebase permite que você altere commits de várias maneiras, como editando, excluindo e mesclando. Você não só pode alterar a mensagem do commit, mas também pode alterar o código real se cometeu um erro. É uma ferramenta poderosa que lhe dá controle total sobre a história de commits do seu projeto.
Como posso mesclar commits usando o Git Interactive Rebase?
O squash é o ato de combinar vários commits em um só. No Git, você pode fazer squash de commits usando o comando git rebase -i
seguido do hash do commit que deseja squashar. No editor de texto que é aberto, você pode marcar os commits que deseja squashar substituindo pick
por squash
ou s
ao lado de cada commit.
Quais são os riscos de usar o Git Interactive Rebase?
Embora o Git Interactive Rebase seja uma ferramenta poderosa, pode ser perigoso se não for usado corretamente. Ele reescreve a história do commit, o que pode ser problemático se você estiver trabalhando em uma branch pública em que outras pessoas também estão trabalhando. Recomenda-se usar em branches locais que ainda não foram enviadas.
Como posso resolver conflitos durante um Git Rebase?
Durante um rebase, podem ocorrer conflitos. O Git pausará e permitirá que você resolva esses conflitos antes de continuar. Você pode resolver conflitos editando os arquivos para corrigir as mudanças conflitantes e, em seguida, adicionando os arquivos resolvidos com git add
. Após resolver todos os conflitos, você pode continuar o rebase com git rebase --continue
.
Posso usar o Git Interactive Rebase para dividir um commit?
Sim, você pode usar o Git Interactive Rebase para dividir um commit em menores. Isso pode ser útil se você fez várias alterações em um único commit, mas mais tarde decidiu que elas deveriam ter sido commits separados.
Como posso editar uma mensagem de commit usando o Git Interactive Rebase?
Você pode editar uma mensagem de commit durante um rebase interativo. Na lista de commits, substitua pick
por reword
ou r
ao lado do commit que deseja editar. Ao continuar, o Git abrirá um editor de texto para cada commit marcado com reword
, permitindo que você altere a mensagem do commit.
Qual é a diferença entre Git Rebase e Git Pull?
O Git Pull é um comando que busca alterações de um repositório remoto e as mescla na sua branch atual. Por outro lado, o Git Rebase é um comando que move ou combina uma sequência de commits para um novo commit base. Embora ambos os comandos sejam usados para integrar alterações, eles fazem isso de maneiras diferentes.
Posso usar o Git Interactive Rebase para mudar a ordem dos commits?
Sim, você pode mudar a ordem dos commits usando o Git Interactive Rebase. Na lista de commits, basta alterar a ordem das linhas para mudar a ordem dos commits. Isso pode ser útil se você quiser tornar sua história de commits mais lógica ou clara.
Source:
https://www.sitepoint.com/git-interactive-rebase-guide/