-
1. Primeiros Passos
- 1.1 Sobre Controle de Versão
- 1.2 Uma Breve História do Git
- 1.3 O que é Git?
- 1.4 A Linha de Comando
- 1.5 Instalando o Git
- 1.6 Configuração inicial do Git
- 1.7 Obtendo Ajuda
- 1.8 Resumo
-
2. Fundamentos do Git
-
3. Ramificação (Branching) no Git
-
4. Git no Servidor
- 4.1 Os Protocolos
- 4.2 Colocando o Git em um Servidor
- 4.3 Gerando a sua Chave Pública SSH
- 4.4 Configurando o Servidor
- 4.5 Git Daemon
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Opções de Hospedagem de Terceiros
- 4.10 Resumo
-
5. Git Distribuído
-
6. GitHub
-
7. Ferramentas do Git
- 7.1 Seleção de Revisão
- 7.2 Área de Stage Interativa
- 7.3 Fazendo Stash e Limpando
- 7.4 Assinando Seu Trabalho
- 7.5 Pesquisando (Searching)
- 7.6 Reescrevendo o Histórico
- 7.7 Reset Desmistificado
- 7.8 Merging Avançado
- 7.9 Rerere
- 7.10 Depurando com Git
- 7.11 Submódulos
- 7.12 Empacotando (Bundling)
- 7.13 Substituir (Replace)
- 7.14 Armazenamento de Credenciais
- 7.15 Resumo
-
8. Customizando o Git
- 8.1 Configuração do Git
- 8.2 Atributos do Git
- 8.3 Hooks do Git
- 8.4 Uma Política de Exemplo Imposta pelo Git
- 8.5 Resumo
-
9. Git e Outros Sistemas
- 9.1 Git como Cliente
- 9.2 Migrando para o Git
- 9.3 Resumo
-
10. Git Internals (Por Dentro do Git)
- 10.1 Encanamento e Porcelana (Plumbing and Porcelain)
- 10.2 Objetos do Git
- 10.3 Referências do Git
- 10.4 Arquivos de pacote (Packfiles)
- 10.5 Refspec
- 10.6 Protocolos de Transferência
- 10.7 Manutenção e Recuperação de Dados
- 10.8 Variáveis de Ambiente
- 10.9 Resumo
-
A1. Appendix A: O Git em Outros Ambientes
- A1.1 Interfaces Gráficas
- A1.2 Git no Visual Studio
- A1.3 Git no Visual Studio Code
- A1.4 Git no IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine
- A1.5 Git no Sublime Text
- A1.6 Git no Bash
- A1.7 Git no Zsh
- A1.8 Git no PowerShell
- A1.9 Resumo
-
A2. Appendix B: Incorporando o Git nos seus Aplicativos
- A2.1 Linha de Comando do Git
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
A3. Appendix C: Comandos do Git
- A3.1 Configuração e Ajustes
- A3.2 Obtendo e Criando Projetos
- A3.3 Snapshots Básicos
- A3.4 Branches e Merges
- A3.5 Compartilhando e Atualizando Projetos
- A3.6 Inspeção e Comparação
- A3.7 Depuração
- A3.8 Patches
- A3.9 E-mail
- A3.10 Sistemas Externos
- A3.11 Administração
- A3.12 Comandos de Encanamento
7.9 Ferramentas do Git - Rerere
Rerere
A funcionalidade git rerere é um pouco uma funcionalidade oculta.
O nome significa “reutilizar a resolução gravada” (reuse recorded resolution) e, como o nome indica, ele permite que você peça ao Git para lembrar como você resolveu um conflito de hunk para que da próxima vez que ele vir o mesmo conflito, o Git possa resolvê-lo para você automaticamente.
Há uma série de cenários em que esta funcionalidade pode ser muito útil.
Um dos exemplos mencionados na documentação é quando você deseja garantir que uma branch de tópico de longa duração, no final das contas, faça o merge perfeitamente, mas você não quer ter um monte de commits de merge intermediários sobrecarregando seu histórico de commits.
Com o rerere habilitado, você pode tentar o merge ocasional, resolver os conflitos, depois recuar o merge.
Se você fizer isso de forma contínua, o merge final deve ser fácil porque o rerere pode simplesmente fazer tudo para você automaticamente.
Esta mesma tática pode ser usada se você quiser manter uma branch rebased, assim não terá que lidar com os mesmos conflitos de rebase a cada vez que o fizer. Ou se você quiser pegar uma branch que você fez o merge e consertou um monte de conflitos e então decidir fazer rebase em vez disso — você provavelmente não terá que fazer todos os mesmos conflitos novamente.
Outra aplicação de rerere é quando você faz o merge ocasional de um bando de branches de tópicos em evolução, para formar uma head de testes, como o próprio projeto Git faz frequentemente.
Se os testes falharem, você pode rebobinar os merges e refazê-los sem a branch de tópico que fez os testes falharem, sem precisar re-resolver os conflitos novamente.
Para habilitar a funcionalidade rerere, você simplesmente tem que rodar essa configuração:
$ git config --global rerere.enabled true
Você também pode ativá-lo criando o diretório .git/rr-cache em um repositório específico, mas a configuração (config) é mais clara e permite ativar este recurso globalmente para você.
Agora, vamos ver um simples exemplo, semelhante ao nosso anterior.
Digamos que temos um arquivo chamado hello.rb parecido com isso:
#! /usr/bin/env ruby
def hello
puts 'hello world'
end
Em uma branch alteramos a palavra “hello” para “hola”, e na outra alteramos “world” para “mundo”, como antes.
Quando nós fizermos o merge em ambas branches, obteremos um conflito de merge:
$ git merge i18n-world
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Recorded preimage for 'hello.rb'
Automatic merge failed; fix conflicts and then commit the result.
Você deve ter notado a nova linha Recorded preimage for FILE aí.
Sem isso, ela se pareceria exatamente com um normal conflito de merge.
Neste ponto, o rerere pode nos dizer algumas coisas.
Normalmente, você pode executar git status neste momento para ver quais deram conflito:
$ git status
# On branch master
# Unmerged paths:
# (use "git reset HEAD <file>..." to unstage)
# (use "git add <file>..." to mark resolution)
#
# both modified: hello.rb
#
Entretanto, git rerere vai te dizer para qual estado o pre-merge foi gravado, por meio de git rerere status:
$ git rerere status
hello.rb
E o git rerere diff irá exibir a situação atual da resolução — o que você começou para resolver e o que você solucionou.
$ git rerere diff
--- a/hello.rb
+++ b/hello.rb
@@ -1,11 +1,11 @@
#! /usr/bin/env ruby
def hello
-<<<<<<<
- puts 'hello mundo'
-=======
+<<<<<<< HEAD
puts 'hola world'
->>>>>>>
+=======
+ puts 'hello mundo'
+>>>>>>> i18n-world
end
Também (e isto não está realmente relacionado com o rerere), você pode usar o git ls-files -u para ver os arquivos em conflito e as versões anterior, esquerda e direita:
$ git ls-files -u
100644 39804c942a9c1f2c03dc7c5ebcd7f3e3a6b97519 1 hello.rb
100644 a440db6e8d1fd76ad438a49025a9ad9ce746f581 2 hello.rb
100644 54336ba847c3758ab604876419607e9443848474 3 hello.rb
Agora você pode resolve-lo para ser simplesmente puts 'hola mundo' e executar o comando git rerere diff novamente, para ver o que o rerere vai se lembrar:
$ git rerere diff
--- a/hello.rb
+++ b/hello.rb
@@ -1,11 +1,7 @@
#! /usr/bin/env ruby
def hello
-<<<<<<<
- puts 'hello mundo'
-=======
- puts 'hola world'
->>>>>>>
+ puts 'hola mundo'
end
Sendo assim, bascicamente ele diz, quando o Git enxergar um conflito de hunk em um arquivo hello.rb que contenha “hello mundo” de um lado e “hola world” do outro, ele o resolverá como “hola mundo”.
Agora podemos marcá-lo como resolvido e realizar o commit dele:
$ git add hello.rb
$ git commit
Recorded resolution for 'hello.rb'.
[master 68e16e5] Merge branch 'i18n'
Você pode ver que ele gravou a resolução para o ARQUIVO ("Recorded resolution for FILE").
Agora, vamos desfazer aquele merge e em seguida dar rebase em nossa branch master.
Para isso, devemos recuar nossa branch por meio de git reset conforme vimos em Reset Desmistificado.
$ git reset --hard HEAD^
HEAD is now at ad63f15 i18n the hello
Nosso merge está desfeito. Agora vamos fazer o rebase da branch de tópico.
$ git checkout i18n-world
Switched to branch 'i18n-world'
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: i18n one word
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Resolved 'hello.rb' using previous resolution.
Failed to merge in the changes.
Patch failed at 0001 i18n one word
Pronto, nós tivemos o mesmo conflito de merge conforme esperávamos, mas dê uma olhada na linha Resolved FILE using previous resolution.
Ao olhar o arquivo, nós veremos que ele já foi resolvido, pois não existem marcadores de conflitos nele.
#! /usr/bin/env ruby
def hello
puts 'hola mundo'
end
Além disso, git diff mostrará a você como ele foi automaticamente resolvido de novo (re-resolved):
$ git diff
diff --cc hello.rb
index a440db6,54336ba..0000000
--- a/hello.rb
+++ b/hello.rb
@@@ -1,7 -1,7 +1,7 @@@
#! /usr/bin/env ruby
def hello
- puts 'hola world'
- puts 'hello mundo'
++ puts 'hola mundo'
end
Nós podemos recriar o arquivo num estado de conflito com o git checkout:
$ git checkout --conflict=merge hello.rb
$ cat hello.rb
#! /usr/bin/env ruby
def hello
<<<<<<< ours
puts 'hola world'
=======
puts 'hello mundo'
>>>>>>> theirs
end
Nós já vimos um exemplo disto em Merging Avançado.
Mas agora, vamos re-resolvê-lo executando novamente o git rerere:
$ git rerere
Resolved 'hello.rb' using previous resolution.
$ cat hello.rb
#! /usr/bin/env ruby
def hello
puts 'hola mundo'
end
Nós re-resolvemos o arquivo automaticamente com a ajuda do armazenamento cache de soluções do rerere.
Agora você pode adicionar e continuar o rebase para completá-lo.
$ git add hello.rb
$ git rebase --continue
Applying: i18n one word
Portanto, se você fizer vários re-merges, ou quer manter as suas branch de tópicos atualizadas com o seu branch principal sem um monte de merges, ou você faz rebase com frequência, você pode ligar o rerere para fazer com que a sua vida fique um pouco mais fácil.