Closed helmedeiros closed 11 years ago
A facilidade em se trabalhar com branches é um dos maiores trunfos do git. Um branch representa uma linha independente de desenvolvimento. Você pode considerá-los como uma forma de solicitar um novo diretório de trabalho, área e histórico do projeto. Toda nova adição e commit são registrados na história do ramo atual, o que resulta em uma bifurcação na história do projeto.
Para começarmos a entender toda a mecânica por trás dos branches nada melhor do que ferramentas para visualizarmos suas criações, distanciação ou aproximação dos demais branchs, principalmente em relação ao master.
Por padrão o git já vem integrado a ferramenta gitk. Para acioná-la:
$ gitk
Uma opção interessante é manter o gitk rodando em background realizando reload das informações quando desejado.
$ gitk&
Esta ferramenta nos apresenta informações sobre o commit:
Além disso poderemos acompanhar as árvores de integração entre branches, mostrando em que estado de versionamento estamos:
Nossa árvore de progressão até então esta exibindo apenas um caminho sem bifurcações ou caminhos paralelos, que corresponderão aos nossos branches, mas para que iremos querê-los?
Em alguns momentos desejamos desenvolver novas funcionalidades, sejam para testar hipóteses ou apenas memorizar uma possível ideia, sem que nenhuma alteração seja memorizada em minha linha central de versionamento, mantendo builds e deploys funcionais enquanto trabalhamos nestes experimentos.
Durante todas as etapas anteriores já estávamos utilizando um branch chamado master que funcionalmente no SVN corresponde ao trunk, mas na verdade possuí várias diferenças.
Para sabermos em que branch estamos, utilizamos o comando branch:
$ git branch
* master
Repare que assim como o gitk a cima, aqui só temos como definido uma única ramificação - master.
Para criarmos o nosso primeiro novo branch utilizaremos novamente o comando branch agora informando o seu nome:
$ git branch nova-funcionalidade
Após o comando o novo branch é criado, mas você permanecerá no branch master. Executando o comando visto anteriormente para listar branchs assim como o gitk, garantem que o mesmo foi criado; veja:
Veja que o branch master e o "nova-funcionalidade" são apresentados no mesmo nível no gitk, isso significa que os mesmo são iguais, dado que o "nova-funcionalidade" foi criado como uma cópia do master.
Aqui é importante informar que os dois apesar de iniciarem iguais, poderão progredir totalmente separados.
Como vimos anteriormente, mesmo tendo criado um novo branch continuávamos no master. Após a criação de um novo branch utilize o comando checkout para definí-lo como o seu ponto de desenvolvimento.
$ git checkout nova-funcionalidade
Switched to branch 'nova-funcionalidade'
Se verificarmos o branch que estamos agora veremos o novo branch marcado como atual selecionado:
$ git branch
master
* nova-funcionalidade
Agora é hora de fazermos as alterações que desejamos, e esperar que as mesmas se reflitam de alguma forma em nossa árvore de versões no gitk.
$ touch mnb.sh
$ git add .
$ git commit -v
[nova-funcionalidade c9a7a32] Adicionado novo script
0 files changed
create mode 100644 mnb.sh
Veja, os dois repositórios agora estão desencontrados, o repositório nova-funcionalidade está a frente com o commit c9a7a32
Perceba que se você fizer checkout neste momento voltando para o branch master, não deverá estar presente nenhum resquicio das alterações que acabamos de executar dentro do branch nova-funcionalidade:
Este isolamento entre os branches é esperado e providencial para o seu funcionamento e propósito.
Podemos explorar ainda mais esta propriedade realizando uma alteração no master e verificando os reflexos da mesma em relação aos gráficos de versões.
Veja que agora temos dois ramos bem separados, que mostram a completa independência em termos de alterações e controles sobre as mesmas.
É muito importante que estejamos sempre de olho no que acontece no master, dado que a maioria dos processos envolvem o mesmo como local de igualdade ao código enviado a produção. Para isso temos o comando rebase.
Primeiramente para fazermos o rebase, precisamos retornar ou já nos encontrarmos no repositório a qual se destina a alteração final:
$ git checkout nova-funcionalidade
Switched to branch 'nova-funcionalidade'
Em seguida, executamos o comando rebase selecionando o repositório do qual queremos trazer as mudanças:
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: Adicionado novo script
O rebase re-organiza o branch atual para aplicar todas as alterações do branch selecionado sobre o branch atual, deixando os commits com diferença sobre os mesmos por último.
Estamos com o fluxo bem parecido ao como estávamos lá no início.
Após várias alterações, vai existir um momento em que você irá desejar retornar suas alterações para o master.
O primeiro passo para realizar este retorno é verificar a diferença entre os dois branches. O comando diff é o responsável por exibir para que possamos descobrir oque será feito quando mesclarmos os branches.
$ git diff master nova-funcionalidade
Em seguida executamos a mescla dos branches por meio do comando merge. Neste comando selecionamos apenas o branch do qual traremos as alterações.
$ git merge nova-funcionalidade
Caso desejemos reverter as mudanças realizadas no merge, mantendo os dois separados por algum momento, podemos utilizar o comando visto anteriormente reset --hard:
$ git reset --hard ORIG_HEAD
HEAD is now at c6864da Definido scripts como tal.
Após este comando estamos prontos para trabalhar todas as alterações desejadas novamente, concluindo ou não o merge após estas.
Em vários momentos quando você tentar realizar o merge existirão conflitos. Para estes casos existem ferramentas melhores para serem utilizadas mas em via de regra, você:
Para realizarmos a listagem dos branchs existentes, basta:
$ git branch
Caso houver a necessidade de excluir um branch:
$ git branch -D branch_name
Para renomear um branch:
$ git branch -m branch_name new_branch_name