Usando o Git – parte 6

git-6_abertura

A parte anterior consistiu basicamente em um navegar pelo histórico dos commits com recolocando a HEAD em outros posições e até mesmo destacando-a da linha do tempo para testar modificações sem necessariamente precisar armazená-las. Para esta parte, o uso do stash para armazenar temporariamente arquivos de trabalho e um exemplo do uso do rebase para modificar um commit já existente — neste caso alterar a mensagem deste.

“Escondendo” os arquivos

O Git possui uma área intermediária onde é possível armazenar — ou, na tradução literal, esconder — arquivos que estão em edição na index mas que por algum motivo não precisam/podem estar em um commit ainda. Por exemplo, no repositório da Pastelaria há um arquivo que foi deixado vazio, o “sobremesas.md” e ao qual resolvi acrescentar algum conteúdo:

## Sobremesas

Mousse de Chocolate

Sorvete de Creme

Pudim de Leite Condensado

Daí é submeter e salvar as alterações e mandá-la para o repositório remoto:

$ git add sobremesas.md
$ git commit -m "adição das sobremesas ao cardápio"
[master b6c1e63] adição das sobremesas ao cardápio
 1 file changed, 8 insertions(+)
$ git push origin master
Counting objects: 3, done.
...
To git@github.com:plainspooky/pastelaria.git
 38c83e0..b6c1e63 master -> master

E voltar a editar o arquivo só para acrescentar alguma outra sobremesa, brigadeiro por exemplo, e mais alguns outros itens que ainda não estão disponíveis e como não há urgência é possível deixá-las quietas no repositório por enquanto:

$ git status
No ramo master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
...
    modified: sobremesas.md

nenhuma modificação adicionada à submissão (utilize "git add" e/ou
"git commit -a")

Porém há uma alteração urgente para ser submetida que precisa ser feita e daí você deixa a edição das sobremesas de lado e vai cuidar dela e, porém…

$ git pull
Updating b6c1e63..d1090cd
error: Your local changes to the following files would be overwritten
by merge:
    sobremesas.md
Please, commit your changes or stash them before you can merge.
Aborting

Enquanto você editava o “sobremesas.md” alguém fez uma alteração nele e já o submeteu¹. E agora, o que fazer? Colocar esta alteração incompleta mesmo em um novo commit? Copiar o arquivo para outro canto e retorná-lo para a versão do último commit? Ou apenas executar o git checkout e descartar as mudanças? Dependendo da situação todas elas são válidas mas há o “jeito do Git” para resolver este problema:

$ git stash save sobremesas.md
Saved working directory and index state On master: sobremesas.md
HEAD is now at b6c1e63 adição das sobremesas ao cardápio

Não só esta versão do “sobremesas.md” foi armazenada em um área a parte (e segura) dentro do repositório (nada de “/tmp”) como automaticamente a HEAD já foi colocada na posição do último commit e permitindo voltar ao processo de atualização do repositório local com o que está no remoto.

$ git pull
Updating b6c1e63..d1090cd
Fast-forward
 sobremesas.md | 2 ++
 1 file changed, 2 insertions(+)

Agora a tal modificação urgente pode ser realizada, submetida e enviada ao repositório remoto.

Mas e quanto ao arquivo que foi escondido? Fácil, ele está onde foi deixado:

$ git stash list
stash@{0}: On master: sobremesas.md

E pode ser retirado a qualquer momento de lá:

$ git stash pop stash@{0}
Mesclagem automática de sobremesas.md
No ramo master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
 (utilize "git add ..." para atualizar o que será
 submetido)
 (utilize "git checkout -- ..." para descartar mudanças
 no diretório de trabalho)

    modified: sobremesas.md

nenhuma modificação adicionada à submissão (utilize "git add" e/ou
"git commit -a")
Dropped stash@{0} (5552a6de88e149226718abe82cdfdc840ca7388f)

Neste caso as alterações foram automaticamente mescladas no arquivo “sobremesas.md” e o arquivo foi removido da lista do stash e as modificações (re)inseridas novamente ao arquivo:

$ git diff sobremesas.md
diff --git a/sobremesas.md b/sobremesas.md
index 6cb7bdc..d3a57f3 100644
--- a/sobremesas.md
+++ b/sobremesas.md
@@ -1,5 +1,7 @@
 ## Sobremesas
 
+Brigadeiro
+
 Mousse de Chocolate
 
 Sorvete de Chocolate

(¹) Sim, há muitas vantagens em se trabalhar diretamente dentro de  branches, uma delas é justamente evitar que este tipo de coisa aconteça.

Utilizando o rebase

Na parte anterior foram feitos dois commits com a HEAD “solta”. Um deles — 1602fad — foi adicionado ao ramo master com o uso do git merge mas o outro² — 2652c6c — ainda se encontra perdido dentro do repositório local. Normalmente seria o caso de mesclar também este commit mas desta vez usarei o rebase para tal finalidade.

Motivo? Apenas aproveitar para editar a mensagem utilizada no commit. 🙂

$ git checkout 2652c6c
Note: checking out '2652c6c'.
...
HEAD is now at 2652c6c... Inclusão do pastel de brócolis no cardápio
$ git rebase --interactive master

Ao executar o comando o editor padrão será aberto e nele o roteiro do que será realizado, neste caso minha lista possui um único commit listado e uma ação padrão — pick — de várias que podem ser tomadas neste caso (a lista está logo abaixo no próprio documento).

git-6_rebase_interactive

Neste caso específico a ação a ser tomada é reword, para alterar o texto do commit, então basta selecionar a ação (tanto aqui faz trocar pick por reword ou apenas colocar a letra ‘r’), salvar o arquivo e sair do editor.

error: não foi possível aplicar 2652c6c... Inclusão do pastel de
brócolis no cardápio

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase
--abort".
Could not apply 2652c6cc96120d6e5f8366db13694ed6e1a4634d...
Inclusão do pastel de brócolis no cardápio

O que aconteceu aqui é um conflito na hora de unir as alterações no arquivo, isto é, o Git tem duas modificações em uma mesma linha e como ele não faz a menor ideia do que deve ser feito neste ponto será preciso a intervenção humana. Isto aconteceria tanto com o uso do rebase quanto do merge.

E como sempre, maiores detalhes pode ser obtidos com o comando git status:

$ git status
interactive rebase in progress; onto d9f55d3
Last command done (1 command done):
  reword 2652c6c Inclusão do pastel de brócolis no cardápio
No commands remaining.
Você está sendo rebaseado agora.
  (corrija os conflitos e então rode "git rebase --continue")
  (use "git rebase --skip" para ignorar este patch)
  (use "git rebase --abort" para verificar o ramo original)

Caminhos não mesclados:
  (use "git reset HEAD ..." to unstage)
  (usar "git add ..." para marcar resolução)

    ambos modificados: README.md

nenhuma modificação adicionada à submissão (utilize "git add" e/ou
"git commit -a")

Neste caso ela pode ser abortada — git rebase --abort — e assim ser revertida ao estado original ou então editar o arquivo “README.md” para corrigir manualmente problema — que neste caso é a opção escolhida.

E felizmente o problema neste arquivo é simples:

...
[Pastel de queijo](pastel_de_queijo.md)
<<<<<<< HEAD
[Pastel de ricota](pastel_de_ricota.md)
=======
[Pastel de brócolis e bacon](pastel_de_brocolis_e_bacon.md)
>>>>>>> 2652c6c... Inclusão do pastel de brócolis no cardápio

## Pastéis doces
...

Na parte de cima é o que está sendo trazida, a HEAD, enquanto que na parte de baixo abaixo é aquilo que já existia no arquivo. Alguns editores, como é o caso do Atom,  interpretam apresentam esta mesma informação de modo diferente e até simplificam a operação de seleção de qual parte utilizar

No caso deste arquivo em markdown a solução é simples, basta remover estas marcas e está resolvido — mas geralmente a solução pode ser bem mais complexa.

Daí é salvar o arquivo e:

$ git add README.md
$ git rebase --continue

Para todo os efeitos será como um novo commit e como foi marcado que o texto seria modificado o editor é aberto para tal.

git-6_rebase_final

E pronto!

[detached HEAD 83b50cd] Novo pastel no cardápio.
 1 file changed, 2 insertions(+)
Successfully rebased and updated detached HEAD.

NEste caso foi criado um novo commit com a mensagem alterada e este incluído na master.

(²) Por estar solto, este tipo de commit acaba não sendo replicado no repositório remoto.

E para finalizar

Para terminar, claro, o envio de todas as atualizações efetuadas localmente para o repositório remoto:

$ git push origin master
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 354 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local
object.
To git@github.com:plainspooky/pastelaria.git
 d1090cd..d9f55d3 master -> master

E, a princípio, era este o complemento da publicação que acabou virando parte dela mesma. Claro que ficou longe de cobrir todos os recursos disponíveis na ferramenta mas ao menos conseguiu ficar próximo daquilo que é necessário para usar efetivamente o Git.

Até!

Anúncios

Um comentário sobre “Usando o Git – parte 6

  1. Pingback: Modificando commits do Git | giovannireisnunes

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s