Seja bem vindo a mais uma ~gentil~ introdução ao git. Hoje, nós vamos aprender a como fazer um rebase de presença e deixar a nossa árvora de commits um pitelzinho.
Antes de começar, vamos lembrar do nosso planejamento de posts:
- O que é o GIT e como usar
- Principais comandos do git
- Como fazer um rebase de presença ⟵ você está aqui
- Como escrever um README.md
- Boas práticas para utilizar o git
Porque essa é uma introdução bem gentil, vamos dividir o conteúdo sobre nosso rebase em algumas partes. O que é uma branch? O que é um rebase e como ele funciona? Quais são as opções de um rebase interativo? Um pequeno exemplo de como fazer um rebase para conquistar o coração daquele pichadão/tchutchuca que tá te filmando e quer ser seu namorado.
O que é uma branch?
Quando nós fazemos um commit, git cria um objeto que indica quais mudanças foram feitas. Esse objeto tem um monte de informação interessante como autor, horário, hash e os pais do commit.
Uma branch é, apenas, um ponteiro para algum desses commits. Ao fazer um commit, é adicionado um novo nó nessa árvore e o ponteiro é deslocado para esse novo nó. E quandos nós criamos uma nova branch, nós estamos apenas criando um novo ponteiro apontando para aquele commit. A imagem abaixo mostra isso.
Temos três commits, 98ca9, 34ac2 e f30ab. Inicialmente, tínhamos uma única branch (master) apontando para o commit f360ab. Após o comando git checkout -b testing
criamos a branch testing que também aponta para o mesmo local.
Se nós estivermos na branch testing e fizemos um commit (vamos chamar de 87ab2), a testing irá apontar para esse novo commit, enquanto a branch master continuará apontando para o f30ab.
Além disso, existe ponteiro especial chamado HEAD que aponta para a branch que nós estamos trabalhando. O movimento desse ponteiro poderá alterar os arquivos nós estamos vendo no nosso diretório de trabalho. E nós movimentamos o HEAD através do comando git checkout <hash do commit ou nome da branch>
Na imagem abaixo, reunimos tudo o que vimos até agora. As branchs master e testing (com seus commits) e o ponteiro HEAD.
Num outro post nós vimos o funcionamento do checkout. Agora nós conseguimos entender melhor o que ele faz. Ao usar o checkout, nós estamos movimentando a HEAD. É possível movimentar tanto entre branchs quanto entre commits. Quando fazemos essa movimentação, o git pode alterar, adicionar ou remover arquivos. E o git sabe sempre como se achar porque dentro do objeto dos commits tem todas as informações importantes para ele trabalhar fazer o que precisa ser feito.
Na imagem abaixo, nós fizemos um git checkout master
e fomos para a branch master. Depois disso, criamos um novo commit (c2b9e). Desse ponto em diante, as duas branchs começam a divergir e terão um ancestral comum (f30ab).
Agora vem a parte mágica.
O que é um rebase e como ele funciona?
A operação de rebase reaplica os commits já feitos em um árvore à partir de um determinado commit ou de uma determinada branch.
Na sua versão mais básica um rebase pode ser utilizado para sincronizar duas branchs (como o git merge
) com a diferença que, enquanto o git merge gera um novo commit unindo as duas branchs. O rebase aplica todos os commits novos em cima dos commits já existentes de uma branch.
Vamos deixar os exemplos acima de lado e vamos trabalhar com um exemplo mais simplificado ainda (que tem uma pequena mentirinha explicada melhor no fim desse post). Aqui temos duas branchs (master e testing) e elas tem um ansestral e comum (commit E).
A---B---C testing
/
D---E---F---G master
Se nós estivermos na branch testing e fizermos o comando
git rebase master
A árvore da branch testing ficará*:
D---E---F---G---A---B---C
Isso é, o git pegou todo o conteúdo branch master e, depois dele, colocou o conteúdo da branch testing.
Um detalhe importante é que se passarmos uma branch ao invés de um commit como parâmetro para o git rebase, então o commit considerado será o commit do topo daquele rebase.
Na sua forma super-ultra-plus-master-advanced, o rebase vira o rebase interativo. Nessa forma, podemos fazer alterações nos commits antes de aplicarmos eles. Vamos ver algo essas alterações.
Quais são as opções de um rebase interativo?
Para fazermos um rebase interativo, nós precisamos apenas adicionar o parâmetro -i no nosso rebase. Quando fazemos isso, o git irá abrir o editor de texto padrão com um arquivo especial chamado git-rebase-todo. Esse arquivo contém todos os commits que serão utilizados para o rebase (sendo referenciados pelo seus hashs e suas mensagens de commit) e qual operação que será feita com ele (na parte de exemplos, vamos dar uma olhada na cara desse arquivo).
Nesse arquivo, nós podemos reordenar os commits, remover os commits ou escolher qual operação aplicar. As operações são:
- p, pick = utilizar o commit
- r, reword = utilizar o commit, mas alterando a mensagem de commit
- e, edit = utilizar o commit, mas parando para fazer alguma alteração (como adicionar ou remover algum elemento do commit)
- s, squash = utilizar o commit, mas juntar as alterações com o commit anterior (se dois commits alterarem o mesmo arquivo, a alteração mais recente será utilizada)
- f, fixup = semelhante ao squash, mas ignorando a mensagem de commit
- x, exec = executar algum comando shell
- d, drop = remover o commit
Um pequeno exemplo de como fazer um rebase para conquistar o coração daquele pichadão/tchutchuca que tá te filmando e quer ser seu namorado
Se você não é a musa do verão, então você precisa ralar para conseguir um bom cobertor de orelhas. E a melhor forma de fazer isso é falar sobre as operações de rebase do git para aquela pessoa que você está de olho.
E pra te dar uma mão nesse plano, vou apresentar aqui um pequeno exemplo de um rebase interativo.
Imagine a situação, você abriu um pull request e o revisor pediu um monte de alterações. Você comita as alterações e ele pede outras. Por fim, ele diz "faz um squash e um push aí das alterações para ter um histórico limpo".
O que ele quer é que todos os commits do tipo "ajustes do PR" sejam colocados como um único commit e, se for o caso, alterar a mensagem para representar as alterações feitas.
Após todas as revisões, o histórico de commits antes do rebase era algo mais ou menos assim:
Como foram feito 6 commits, nós precisamos fazer um rebase interativo à partir de 6 commits anteriores ao ponteiro da HEAD. Fazemos isso com o comando git rebase -i HEAD~6
.
Isso vai abrir a tela de alteração dos commits. Daí nós só precisamos marcar os commits que não são o primeiro como squash.
Após salvar e fechar, o git vai abrir a tela para nós editarmos a mensagem de commit. Nessa tela, todas as mensagens de commit que sofreram o squash estarão presentes. Com isso é só colocar a mensagem de commit que você quer e voilá. No final, a árvore de commits ficará mais ou menos assim:
Por fim, na hora de devolver as alterações para a branch remota (aka. fazer um push), será necessário usar o parâmetro -f para reescrever o histórico. Ficará assim git push -f
Mais informações legais podem ser encontrados lá na documentação oficial do git (e foi da documentação dos branchs que eu peguei as imagens usadas)
Nota: Sendo bem preciosista, os novos *commits não serão A,B,C mas commits com mesmas alterações e mensagens de commit. Porém, o hash será diferente já que o pai do commit é diferente.
Top comments (1)
Muito top!