Usando o Git – parte 2

git-2_git_merge

A primeira parte foi basicamente um exercício do fluxo de trabalho do Git, ou seja, criar/editar um arquivo no working directory, colocar na staging area e então enviar para a HEAD. Mas eu dissera que o conceito é importante, não foi?

Agora é vez de acrescentar mais alguma complexidade com a introdução do conceito de ramificação nos repositórios.

Branch?

De forma bem simples em um branch, ou “ramo”, é um desvio que você produz na história do seu repositório para criar uma espécie de visão “alternativa” que conterá até mesmo seus próprios commits. Observe o exemplo:

Exemplo de branch -- o excesso de cores é totalmente proposital

Exemplo de branch — o excesso de cores é totalmente proposital

Neste caso após aplicar as alterações do “COMMIT 1” no ramo MASTER (verde) se criou um novo branch. Como ele existe no repositório de forma independente deixou de receber as modificações trazidas pelos “COMMIT 2” (amarelo) e “COMMIT 3” (vermelho), ou seja, ele continuou refletindo o estado do “COMMIT 1”.

Como  o branch não é algo estático, pode receber suas próprias alterações, no caso o “COMMIT 4” (azul), que o deixou diferente tanto da visão do passado como também do estado presente do ramo MASTER. E ele pode ainda continuar seguindo um desenvolvimento paralelo com master, ter as modificações mescladas com MASTER (roxo) passando a ficar iguais ou ter suas próprias ramificações.

A principal função de um branch é te permitir desenvolver uma nova funcionalidade, ou um conjunto grandes de modificações, sem necessariamente fazê-lo diretamente no ramo principal ou, o que é pior, copiar o repositório para trabalhar em outro lugar.

De volta à pastelaria

Voltando ao exemplo, a gerência da pastelaria resolveu montar duas equipes de trabalho. Uma responsável por inserir no cardápio os pastéis doces pois “alguém esqueceu de fazê-lo”(correção). E outra encarregada de criar novos recheios para acrescentar ao cardápio (nova funcionalidade). E nestas tarefas cada equipe trabalhará em seu próprio branch.

Antes de começar, de volta à máquina virtual:

$ ~cd /Vagrant/usando_o_git
$ vagrant up --provider virtualbox
$ vagrant ssh

A partir do master serão criadas duas ramificações. Isto é feito com o comando “branch”:

$ git branch cardápio
$ git branch doces
$ git branch
  cardápio
  doces
* master

A função do asterisco é indicar em qual branch nos encontramos.

Após a criação dos branchs a historia do repositório fica assim. O ramo principal, o master (em laranja), os dois commits já aplicados e em seguida as duas ramificações recém criadas, “cardápio” (em roxo) e “doces” (em verde):

Repositório após a criação dos branches -- agora com uso comedido de cores :-)

Repositório após a criação dos branches — agora com uso comedido de cores 🙂

E como nenhuma alteração foi feita a nenhum dos três ramos ambos ainda refletem o estado do último commit — 08df860 — mas isto será por pouco tempo. 🙂

Os pastéis doces

Antes de começar a editar os arquivos alteramos  o branch atual para o “doces”:

$ git checkout doces

Daí inserimos o primeiro pastel doce, o «pastel_de_banana_com_canela.md»:

# Pastel de Banana com Canela

Pastel recheado banana caramelizada com uma pitada de cravo e canela.

__Este pastel vem polvilhado com mistura de canela e açúcar branco__

## Veja também

[Pastel de Chocolate](pastel_de_chocolate.md)

Em seguida o «pastel_de_chocolate.md»:

# Pastel de Chocolate

Pastel recheado com creme de chocolate ao leite.

## Veja também

[Pastel de Banana com Canela](pastel_de_banana_com_canela.md)

E, claro, as alterações necessárias em «README.md» para que eles apareçam no cardápio:

# Pastelaria

Conheça as opções do nosso cardápio!

## Pastéis salgados

[Pastel de carne](pastel_de_carne.md)

[Pastel de queijo](pastel_de_queijo.md)

## Pastéis doces

[Pastel de banana com canela](pastel_de_banana_com_canela.md)

[Pastel de chocolate](pastel_de_chocolate.md)

Adicionar os arquivos, fazer o commit e pronto!

$ git add --all
$ git commit -m "pastéis doces"
[doces 55b2f39] pastéis doces
 3 files changed, 22 insertions(+), 2 deletions(-)
 create mode 100644 pastel_de_banana_com_canela.md
 create mode 100644 pastel_de_chocolate.md

Tarefa concluída, ao menos neste branch.

Os novos pastéis

A equipe dos novos pastéis pensou em dois novos recheios, daí mudaram de branch:

$ git checkout cardápio

Acrescentaram um  novo pastel com carne, o «pastel_de_carne_com_ovo.md»:

# Pastel de Carne com Ovo

Pastel recheado com carne moída temperada com alho, cebola, 
salsa e um leve toque de pimenta do reino com ovos cozidos picados
e ervilhas.

__contém uma azeitona inteira com caroço__

E também um com frango, o «pastel_de_frango_com_curry.md»:

# Pastel de frango com curry

Pastel recheado com pasta de frango cozido desfiado com curry e 
_cream cheese_.

Pois é, ninguém curtiu muito a ideia de ter um pastel de frango com Catupity no cardápio. 🙂

Como não precisavam listá-los no cardápio bastou fazer o commit

$ git add pastel_de_*
$ git commit -m "novos pastéis para teste"
[cardápio f428560] novos pastéis para teste
 2 files changed, 13 insertions(+)
 create mode 100644 pastel_de_carne_com_ovo.md
 create mode 100644 pastel_de_frango_com_curry.md

Tarefa concluída também neste branch.

(¹) Ficou faltando a inclusão dos arquivos que foram criados na index antes de fazer o commit.

E as bebidas?

Sendo um exemplo do “mundo real”, enquanto as equipes cuidavam de suas tarefas a gerência da pastelaria — sempre ela — lembrou que deveria ter algo para as pessoas beberem enquanto consomem seus pastéis e pediu que as bebidas fossem acrescentadas no cardápio:

# Pastelaria

Conheça as opções do nosso cardápio!

## Pastéis salgados

[Pastel de carne](pastel_de_carne.md)

[Pastel de queijo](pastel_de_queijo.md)

## Pastéis doces

Pastel de banana com canela

Pastel de chocolate

## Bebidas

Caldo de Cana

Suco de Laranja

Suco de Maracujá

E que isto fosse disponibilizado logo através de um commit extraordinário — que só aconteceria dessa vez, juro! — no repositório:

$ git add --all
$ git commit -m "inclusão das bebidas"
[master 712db28] inclusão das bebidas
 1 file changed, 8 insertions(+)

Exatamente, alteração feita diretamente no master do repositório.

Mesclando os trabalhos

Com todas as tarefas concluídas é momento de unificá-las. Isto é feito utilizando o comando merge e a primeira modificação a incluir será a dos novos pastéis:

$ git checkout master
$ git merge cardápio -m "mesclando 'cardápio'"
Merge made by the 'recursive' strategy.
 pastel_de_carne_com_ovo.md    | 8 ++++++++
 pastel_de_frango_com_curry.md | 5 +++++
 2 files changed, 13 insertions(+)
 create mode 100644 pastel_de_carne_com_ovo.md
 create mode 100644 pastel_de_frango_com_curry.md

Com elas inseridas com sucesso agora é a vez dos pastéis doces:

$ git merge doces -m "mesclando 'doces'"
Auto-merging README.md
Merge made by the 'recursive' strategy.
 README.md                      |  4 ++--
 pastel_de_banana_com_canela.md | 10 ++++++++++
 pastel_de_chocolate.md         | 10 ++++++++++
 3 files changed, 22 insertions(+), 2 deletions(-)
 create mode 100644 pastel_de_banana_com_canela.md
 create mode 100644 pastel_de_chocolate.md

E deu certo! Mas não deveria ter dado algum erro pois haviam diferenças de conteúdo entre os dois «README.md»?

Pois é, o Git simplesmente mesclou os arquivos do jeito correto e observe no retorno do comando que ele tanto inseriu as duas linhas dos pastéis doces como também removeu as linhas originais.

Em repositórios puramente locais o Git consegue realizar este tipo de operação de forma automática, até porque em caso de problemas basta voltar para a versão anterior — opa, preciso explicar como se faz algo assim mas antes:

$ git branch --delete cardápio doces

Para excluir os branches já que as duas três tarefas foram concluídas.

Recuperando uma versão anterior

Antes de terminar a gerência sugeriu uma mudança no «pastel_de_carne_com_ovo.md» para que ficasse:

# Pastel de Carne com Ovo

Pastel recheado com carne e ovos cozidos picados com cebola, tomate e
passas.

Mais uma vez:

$ git add pastel_de_carne_com_ovo.md 
$ git commit -m "mudança no carne com ovo"
[master 9c46bac] mudança no carne com ovo
 1 file changed, 2 insertions(+), 5 deletions(-)

E agora, após o último commit, o histórico do repositório ficou assim:

Lembrando que cada merge correspondo a um novo commit no repositório

Lembrando que cada merge correspondeu a um novo commit no repositório

Porém, logo após o commit, a gerência mudou novamente de ideia sobre mudar a receita do pastel e pediu que ela retornasse para como era antes — parece que  as pessoas não gostam tanto assim de passas. 🙂

Ou seja, precisamos voltar para a versão do arquivo antes do último commit:

$ git checkout master~1 pastel_de_carne_com_ovo.md

Sim, o checkout foi usado para mudar o branch mas ele tem outras funcionalidades e neste caso o que ele fez foi pegar um commit atrás do último a revisão do arquivo «pastel_de_carne_com_ovo.md»:

git-2_pastelaria_3

O checkout “salta” o último commit para pegar no “passado” o arquivo desejado

Pronto, o conteúdo do arquivo voltou para o que era no penúltimo commit — o 33726d3:

$ cat pastel_de_carne_com_ovo.md 
# Pastel de Carne com Ovo

Pastel recheado com carne moída temperada com alho, cebola, 
salsa e um leve toque de pimenta do reino com ovos cozidos picados
e ervilhas.

__contém uma azeitona inteira com caroço__

Apenas lembrando que foi somente a arquivo (ou arquivos) foi trazido e não todo o repositório. É como se ele tivesse sido redigitado em sua versão anterior na working directory, aliás:

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   pastel_de_carne_com_ovo.md

Ao contrário do merge, o checkout não gerou um novo commit, apenas o colocou na staging area. Cabe a você verificar se é exatamente a versão desejada ou usar git reset «nome do arquivo» para tirá-lo da index.

Já que é a versão correta basta fazer¹:

$ git commit -m "carne com ovo de volta à receita original"
[master 341945d] carne com ovo de volta à receita original
 2 files changed, 8 insertions(+), 7 deletions(-)

Aliás, sempre que uma edição de um arquivo for totalmente perdida² basta usar git checkout «nome do arquivo» para trazê-lo de volta para a revisão do último commit — bem melhor que ficar espalhando cópias de segurança no diretório de trabalho, correto.

(¹) Neste commit foram alterados dois arquivos pois cometi um erro no conteúdo do arquivo «pastel_de_chocolate.md» e, claro, aproveitei esta oportunidade para consertar.

(²) Em (quase) qualquer editor pense na sequência «Ctrl»+«A», «Del», «Ctrl»+«S», “A”, «Ctrl»+«S» e então um «Altl»+«F4», perdido o suficiente? 🙂

Fim desta parte

Além de praticar mais um pouco mais o fluxo de trabalho — algo que será uma constante, foi introduzido o conceito do branches (ramificações) nos repositório para grandes alterações, ou grandes bagunças, no código. A posterior mesclagem de conteúdos para unificar os ramos e o uso do ckeckout para “viajar no tempo” e trazer revisões do passado.

É claro que um repositório distribuído não serve de muita coisa quando ele está em um único local. Na próxima parte será a vez de disponibilizar o repositório.

Anúncios

6 comentários sobre “Usando o Git – parte 2

  1. Pingback: Usando o Git, segunda parte - Linux em Ação XYZ

  2. Pingback: Usando o Git – parte 3 | giovannireisnunes

  3. Olá Giovanni! Excelente (série) de artigos! Parabéns!

    Só por curiosidade: qual software você utilizou para fazer as figuras explicando os branches que está neste artigo?

    Agradeço a atenção!

    Curtir

  4. Pingback: Usando o Git – parte 5 | 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