Trabalhando com branches no Git

maxresdefault

 

Talvez um dos maiores desafios para quem começa a usar o Git é saber como trabalhar com branches.

Até então, enquanto trabalhei com SVN, o conceito de branch era bem diferente. No Git, podemos usar branches para trabalhar isoladamente numa feature ou num bug fixing. Sempre criamos essa branch a partir de alguma origem. Por exemplo, por default, no Git, temos um branch master. Seria como um branch default. Em relação ao SVN seria como o trunk.

É possível trabalhar em muitas formas com o Git. Desde uma forma simples, usando sempre apenas o default, como também usando o Git Flow. Consiste em trabalhar em várias branches paralelas. Podemos ter, por exemplo, uma branch para desenvolvimento, uma para release, uma para hotfix, etc. Além disso, em cima de cada branch dessa, podemos criar branches de “desenvolvimento”. Essas branches sempre serão mergeadas para alguma branch final como master, release, hotfix, etc.

Por exemplo, vamos supor que você vá iniciar uma feature nova, desenvolvendo do zero. Então, a partir da branch master, podemos criar uma nova branch “branch_new_feature”.

Você pode desenvolver nessa branch, e commitar ou dar push normalmente nela.

Umas vez que você deu push e disponibilizou essa branch remotamente, outros usuários também conseguem pegar as alterações dessa branch, mergear em outra branch e continuar o trabalho.

Essa estratégia acaba funcionando bem quando temos features a serem desenvolvidas tanto quando temos mais de um dev na mesma feature quanto quando temos features que são dependentes entre si.

E além disso, garante que seu master fique intacto, sem poluir com features “parciais” que podem conter bugs.

Há quem ache isso ruim, não ter a features disponibilizadas mesmo que parcialmente. Porém, acaba sendo uma boa prática, quando se tem entregas parciais.

De novo, existem n formas de trabalhar com essas ferramentas de versionamento.

Vou citar uma que funcionou bem, num time de 7 desenvolvedores.

Usarei como exemplo um repositório github.

Ao criar repositório, é disponibilizado automaticamente um repositório com branch master.

Diagram1-crop

Criei o repositório, criando por default um arquivo readme. Para um primeiro teste, fiz o clone do repositório:

git clone <url>

Ao executar o comando:

gitk -all

É mostrado um commit inicial com a mensagem mostrada acima.

Modifiquei o readme file, e inseri no repositório (por padrão, estou trabalhando no branch master, sem criar nenhuma nova branch).

Alterei o arquivo e salvei.

Para verificar arquivos alterados, executei o comando:

git status

Para adicionar o arquivo alterado, executei o comando:

git add .

Para comitar o arquivo com mensagem customizada:

git commit -m "changing readme file in master branch"

E dei um push:

git push

Ao verificar no repositório via gitk -all, é possível ver que houve a alteração, com a mensagem de commit que configurei (cada bolinha do diagrama representa uma mudança).

Diagram2-crop

Resolvi então criar uma branch paralela a master, a qual nomiei como release.

git checkout -b release

Modifiquei arquivo, salvei e comitei:

git add .

git commit -m "changing readme file in release branch"

Ao tentar executar push obtive um erro. Como é a primeira vez que tento dar push nessa branch, o comando é um pouco diferente.

git push --set-upstream origin release

Diagram3-crop

Ao visualizar o diagrama do gitk –all, uma nova bolinha foi criada, não mais na reta de master. É uma nova branch, com nome release. E no diagrama acima é possível ver a representação dessa mudança. Na branch release (azul) é possível ver o novo commit, com a mesma mensagem que foi passada no comando.

Vamos supor que agora, eu queria voltar para a branch master. E mais, além de voltar, quero que o que foi feito em release, seja mergeado no master, ou seja, as duas branches terão as mesmas implementações.

Primeiro, preciso mudar de branch, voltar para master:

git checkout master

Para mergear release em master, é necessário fazer um pull:

git pull origin release

Como nas duas branches eu mexi no mesmo arquivo, ocorreu um merge. Resolvi os conflitos e para que esse merge seja finalizado com sucesso, preciso comitar as alterações.

Após salvar arquivo mergeado, executar a seguinte sequência de comandos:

git add .

git commit -m "solving merge"

git push

Diagram4-crop

Ao visualizar como ficou na árvore de alterações, voltamos para master, agora com as alterações de release, conforme o diagrama mostra a bolinha azul voltando para a vermelha.

Agora vamos exemplificar uma alteração mais simples, sem merge.

Para voltar para a branch release, executo o comando de checkout

git checkout release

Vou adicionar um novo arquivo e comitá-lo ainda em release

Crio o arquivo, salvo.

git add .

git commit -m "adding new file in release branch"

git push

Diagram5-crop

Novamente, uma bolinha azul representando release, ainda não vinculada à branch master. Release está à frente de master, ou seja, minha branch de release contém alterações que ainda não existem em master.

Para jogar essas alterações agora em master, devemos dar checkout para master.

git checkout master

Para pegar as alterações de release para master, executar o pull:

git pull origin release

E para finalizar e aplicar essas alterações, executar o push

git push

Veja como fica a representação gráfica no final de toda essa iteração:

FullDiagram

Todo o conteúdo novo de release foi para master.

Essas imagens foram meramente ilustrativas.

Ao executar o comando gitk –all no windows, foi mostrada uma imagem como a que segue abaixo:

gitk

Esse foi apenas um exemplo simples.

Geralmente, em tempo de desenvolvimento, temos vários devs trabalhando em cima de master, por exemplo. Cada um cria sua branch relacionada à sua feature. Conforme vão finalizando as features, as mesmas são integradas em master. Claro que isso pode dar merges, mas funciona bem. Caso você precise gerar entregas intermediárias, você total controle que tudo que está em master, teve seu desenvolvimento finalizado.

Uma outra forma de trabalhar que funciona muito bem, seria ter 3 branches.

Uma de develop, outra de release e uma de hotfix.

Iniciando o Sprint, o Time A começa a trabalhar em cima do develop. Uma vez que todos terminaram as features, começa o processo de validação, migrando então tudo o que estava em develop para release. Todo o Time A agora cria branches em cima da branch release. Fazem correções de bugs em cima dessa branch. Terminada toda a validação e estabilização, é gerada uma entrega e o cliente executa testes ou coloca em produção. Em paralelo a isso o time pode voltar a trabalhar no develop no próximo Sprint. Ou então podemos ter Time B, Time C, etc trabalhando em paralelo (aí está a importância de não se “contaminar” a branch principal, nesse caso, develop). O cliente pode dar feedback de que existe um bug pontual que precisa ser corrigido. Todo o release vai agora para hotfix, o dev vai e corrige em hotfix, libera nova versão, etc. Toda vez que um “processo” desse tipo é finalizado, seja mudar para nova branch ou entrega finalizada, sprint aceito, tudo que está em release e hotfix devem voltar para develop. Todos precisam ficar atentos a sempre estarem no branch certo (isso exige uma comunicação muito boa entre o(s) time(s)).

Com esse tipo de separação de branches também fica mais claro para o time de QA o que validar, quando validar. O que entrou ou não para uma determinada release. Esse modo de trabalhar em branches é conhecido como git flow.

Mas de novo, tudo depende do time. Para alguns times isso é muito difícil de entender, preferem ter um branch só e funciona. Para outros, essa estratégia de ter muitos branches paralelos também funciona super bem. Mas sempre fica uma pessoa encarregada em ajudar o time, comunicar qual a branch que deve ser usada, a release em qual branch vai ser gerada, e além disso, alguém que fique encarregado, ou até mesmo um rodízio no time, de quem vai mergear cada branch onde for preciso a cada etapa do processo, para que nada seja perdido. Lógico que além disso também precisamos ter uma boa integração entre as ferramentas como Jira, Jenkins, etc.

 

Material interessante sobre git flow: https://www.atlassian.com/git/tutorials/comparing-workflows

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios são marcados com *