Git sem complicação: alterando o histórico com rebase — parte II
Or Kamara
17 de junho de 2020
0 minutos de leituraBem-vindo de volta à segunda parte sobre como trabalhar com Git sem complicação!
No artigo anterior, falamos sobre os conceitos básicos do rebase e duas situações comuns que podem surgir ao trabalhar com Git. Você encontra a primeira parte aqui. Nesta parte, vamos abordar mais quatro situações comuns e algumas conclusões.
Vamos direto ao ponto!
Situações comuns (e como lidar com elas!) — parte II
Vamos retomar de onde paramos da última vez, com algumas situações comuns em que você pode querer alterar o histórico do seu código e como fazer isso usando Git:
1. Dividir um commit antigo em dois (edit)
Digamos que você acabou de perceber que cometeu um erro ao juntar 2 commits (veja a parte I para mais detalhes) e quer desfazer o squash de 17a73c1 em e2952e7, para que o novo arquivo fique em um commit diferente. A solução é executar todos os commits até o ponto específico que você quer editar, parar, fazer as alterações e continuar. Ou seja, use a edit opção.
Vamos começar executando git rebase -i master novamente, mas desta vez com a opção edit no commit que queremos dividir (o segundo commit, `6871683`):
Ao sair da tela do rebase, veremos:
Basicamente, o Git executou o primeiro e o segundo commits, parou e agora a bola está com a gente. Podemos fazer todas as alterações que quisermos!
Este é o grafo do Git neste momento:
Como mencionamos antes, queremos dividir o segundo commit em dois commits diferentes, um para cada arquivo. O primeiro passo é desfazer as alterações do segundo commit executando git reset --soft HEAD^. O comando reset altera o commit para o qual a branch HEAD está apontando. Com a opção --soft, mantemos o índice e o diretório de trabalho, enquanto todos os arquivos alterados entre o HEAD original e o commit ficam preparados para commit.
Este é o novo status do Git. Como você pode ver, os dois arquivos estão em stage:
Agora, vamos tirar b2.txt da lista de arquivos em stage executando git restore --staged b2.txt:
Com apenas b.txt em stage, podemos fazer o commit da primeira parte do segundo commit. Depois, colocamos b2.txt em stage e fazemos o commit da segunda parte:
Agora, nosso grafo do Git está assim:
O último passo é continuar o rebase e executar os commits restantes com:
git rebase --continue. O grafo final do Git deve ficar assim:
2. Modificar todos os arquivos em um commit específico (edit)
Você provavelmente conhece a próxima situação: enviou todo o seu código, perfeitamente dividido em vários commits, mas depois percebeu que esqueceu de executar o linter. Como explicamos antes, a solução não é criar outro commit chamado fix linting, mas corrigir o lint em cada commit.
Se a alteração for pequena, podemos usar a opção squash. Mas, se houver várias alterações em vários commits, o melhor é executar o script de lint um a um em cada commit (ou nos commits específicos que queremos corrigir). Para isso, podemos usar novamente a opção edit (como fizemos no exemplo anterior).
Vamos executar git commit rebase -i novamente, usando a opção edit no primeiro commit (um commit com vários arquivos):
Como antes, o Git para depois de executar o primeiro commit:
Agora podemos executar nosso linter (por exemplo, npm run lint) e verificar o status do repositório:
Como você pode ver, o script do linter alterou o conteúdo de 6 arquivos (a*.txt). Agora, basta incorporar as alterações atuais (colocando-as em stage e fazendo o commit) e continuar o rebase:
E o grafo do Git deve ficar assim:
3. Garantir que os testes passem em cada commit (exec)
Ao dividir seu código em vários commits, lembre-se de que cada commit deve ser independente. Em outras palavras, depois de juntar vários commits em uma das branches principais, você deve poder voltar a cada um deles e esperar que o código compile e que todos os testes passem.
Então, como validar isso antes de juntar os commits?
Vamos executar os testes manualmente em cada commit! Brincadeira, é claro — devemos automatizar isso :) Para isso, podemos usar a exec opção.
Essa opção nos ajuda a executar scripts de shell como parte do processo de rebase. Para isso, basta adicionar novas linhas com o comando exec onde quisermos. Por exemplo, vamos executar novamente git rebase -i master :
Agora vem a parte divertida: executar os testes (rodando o script ./run_tests.sh) após cada commit:
E este é o resultado ao sair da janela do rebase:
Como você pode ver, o Git executou o script de testes depois de cada commit. Assim, agora sabemos que algo no commit feat: 2nd commit faz os testes falharem. Também é possível adicionar um único comando exec depois de cada commit executando:
$ git rebase -i --exec "./run_tests.sh"
Por último (na verdade, primeiro): como cancelar
Esta não é exatamente uma situação, mas sim um alerta: o comando rebase pode ser perigoso!Usá-lo sem entender os efeitos dos comandos pode comprometer seu trabalho. Por isso, começo com duas recomendações:
Antes de começar a mexer nos commits, sempre faça um backup adequado do seu repositório Git. O jeito mais simples, para mim, é enviar todas as alterações para uma branch remota. Se algo der errado, posso voltar ao código original (usando
git reset).Tenha certeza de que entende os comandos. Em vez de usá-los pela primeira vez no código real, teste-os antes em um repositório Git temporário.
Lembre-se de que você sempre pode interromper o processo de rebase e voltar ao estado original:
Na tela inicial do rebase, basta apagar todas as linhas dos commits e nada será alterado.
No meio do processo de rebase, se por algum motivo você se perder e não souber o que fazer, pode executar
git rebase --abort. Esse comando interrompe o rebase e restaura o repositório ao estado original (antes de executargit rebase -i).
Para resumir
Como vimos nos últimos exemplos, git rebase é um comando poderoso, especialmente no modo interativo. Há inúmeros casos em que podemos usá-lo, mas espero ter ajudado você a entender quando cada uma das opções é útil.
O principal que gostaria que você levasse deste artigo é que deve usar git rebase com inteligência e confiança. Sei que, no começo, pode dar um pouco de medo, e talvez você queira alguém segurando sua mão na hora de apertar Enter, mas tudo bem. Com a prática, isso vai se tornar parte da rotina. Além disso, tenho certeza de que existem muitos outros cenários específicos para o seu caso em que esse comando pode ser útil.
Aproveite!
Comece a jogar Capture the Flag
Aprenda a resolver desafios de Capture the Flag assistindo à gravação sob demanda do nosso workshop virtual introdutório.



