Mudanças entre as edições de "Modelo de branches no GitLab"
(10 revisões intermediárias pelo mesmo usuário não estão sendo mostradas) | |||
Linha 1: | Linha 1: | ||
+ | [[Arquivo:Git-model.png|thumb]] | ||
+ | [[Arquivo:Metodologia-entregas-ageis.png|thumb]] | ||
O git mudou a forma com a qual os desenvolvedores pensam a respeito de merges e ''branches''. No mundo de código centralizado, merges e ''branches'' sempre foram considerados assustadores (cuidados com os conflitos do merge) e algo que era feito apenas uma vez em um longo tempo. | O git mudou a forma com a qual os desenvolvedores pensam a respeito de merges e ''branches''. No mundo de código centralizado, merges e ''branches'' sempre foram considerados assustadores (cuidados com os conflitos do merge) e algo que era feito apenas uma vez em um longo tempo. | ||
Porém com o git essas ações são extremamente baratas e simples, e são consideradas o cerne do dia-a-dia de trabalho, de verdade. Como uma consequência de sua simplicidade e natureza repetitiva, criar ''branches'' e merges não é algo que se deva ter medo. As ferramentas de versionamento dispõem de toda a assistência necessária para realizar as tarefas de criação de ''branches'' e merges. | Porém com o git essas ações são extremamente baratas e simples, e são consideradas o cerne do dia-a-dia de trabalho, de verdade. Como uma consequência de sua simplicidade e natureza repetitiva, criar ''branches'' e merges não é algo que se deva ter medo. As ferramentas de versionamento dispõem de toda a assistência necessária para realizar as tarefas de criação de ''branches'' e merges. | ||
Linha 4: | Linha 6: | ||
Após essa breve introdução sobre a ferramenta, vamos entrar de cabeça no modelo de desenvolvimento. O modelo aqui apresentado é essencialmente nada mais que um conjunto de procedimentos que cada membro da equipe tem que seguir a fim de chegar a um processo de desenvolvimento de software gerenciado. | Após essa breve introdução sobre a ferramenta, vamos entrar de cabeça no modelo de desenvolvimento. O modelo aqui apresentado é essencialmente nada mais que um conjunto de procedimentos que cada membro da equipe tem que seguir a fim de chegar a um processo de desenvolvimento de software gerenciado. | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
== Descentralizado, mas centralizado == | == Descentralizado, mas centralizado == | ||
+ | [[Arquivo:Centr-decentr.png|thumb]] | ||
O modelo de repositório utilizado para o gerenciamento de ''branches'' considera que temos apenas um único, e verdadeiro, repositório central. Note que este repositório é apenas considerado central (pois como o git é uma ferramenta de controle descentralizado, não existe um repositório central a nível técnico). Vamos nos referir a este repositório principal como '''origin''', pois é um nome familiar a todos os usuários do git. | O modelo de repositório utilizado para o gerenciamento de ''branches'' considera que temos apenas um único, e verdadeiro, repositório central. Note que este repositório é apenas considerado central (pois como o git é uma ferramenta de controle descentralizado, não existe um repositório central a nível técnico). Vamos nos referir a este repositório principal como '''origin''', pois é um nome familiar a todos os usuários do git. | ||
− | |||
− | Cada desenvolvedor efetua ''pull'' e ''pushes'' no ''origin''. Mas, além dessa relação centralizada comum, cada desenvolvedor deve também efetuar um ''pull'' das modificações realizadas por outros desenvolvedores de outras equipes. Por exemplo, isto pode ser útil quando um ou mais desenvolvedores estão trabalhando em uma nova grande funcionalidade, antes de enviar as alterações em progresso diretamente para o repositório ''origin'' prematuramente. Na figura | + | Cada desenvolvedor efetua ''pull'' e ''pushes'' no ''origin''. Mas, além dessa relação centralizada comum, cada desenvolvedor deve também efetuar um ''pull'' das modificações realizadas por outros desenvolvedores de outras equipes. Por exemplo, isto pode ser útil quando um ou mais desenvolvedores estão trabalhando em uma nova grande funcionalidade, antes de enviar as alterações em progresso diretamente para o repositório ''origin'' prematuramente. Na figura ao lado, existem equipes de Alice e Bob, Alice e David, e Clair e David. |
Tecnicamente isto significa nada mais que Alice definiu um ''git remote'' (chamado bob) apontando para o repositório da equipe de Bob, e vice-versa. | Tecnicamente isto significa nada mais que Alice definiu um ''git remote'' (chamado bob) apontando para o repositório da equipe de Bob, e vice-versa. | ||
+ | |||
+ | |||
== O ''branch'' principal == | == O ''branch'' principal == | ||
Linha 23: | Linha 32: | ||
Portanto, cada vez que as alterações são mescladas de volta para o ''master''', esta é uma nova versão de produção por definição. Devemos ser muito rigorosos com isso, de modo que, teoricamente, nós poderíamos usar um ''script'' automático para realizar o ''deploy'' e ''roll-out'' de nosso software para os nossos servidores de produção automaticamente toda vez que houve uma consolidação no ''master''. | Portanto, cada vez que as alterações são mescladas de volta para o ''master''', esta é uma nova versão de produção por definição. Devemos ser muito rigorosos com isso, de modo que, teoricamente, nós poderíamos usar um ''script'' automático para realizar o ''deploy'' e ''roll-out'' de nosso software para os nossos servidores de produção automaticamente toda vez que houve uma consolidação no ''master''. | ||
− | == Os ''branches'' de suporte == | + | |
+ | === Os ''branches'' de suporte === | ||
Ao lado do '''''master''' e '''develop''' branches'', o nosso modelo de desenvolvimento utiliza uma variedade de ''branches'' de apoio para auxiliar o desenvolvimento paralelo entre os membros da equipe, facilitando o rastreamento de recursos, o preparo para versões de produção e para auxiliar na solução rápida de problemas na produção. Ao contrário dos ''branches'' principais, estes sempre tem um tempo de vida limitado, uma vez que eles serão removidos eventualmente. | Ao lado do '''''master''' e '''develop''' branches'', o nosso modelo de desenvolvimento utiliza uma variedade de ''branches'' de apoio para auxiliar o desenvolvimento paralelo entre os membros da equipe, facilitando o rastreamento de recursos, o preparo para versões de produção e para auxiliar na solução rápida de problemas na produção. Ao contrário dos ''branches'' principais, estes sempre tem um tempo de vida limitado, uma vez que eles serão removidos eventualmente. | ||
Os diferentes tipos de ''branches'' que podemos utilizar são: | Os diferentes tipos de ''branches'' que podemos utilizar são: | ||
* ''Feature branches'' | * ''Feature branches'' | ||
* ''Release branches'' | * ''Release branches'' | ||
+ | * ''Hotfix branches'' | ||
Cada um desses ramos têm um propósito específico e estão vinculados a regras restritas sobre quais ''branches'' podem ser seu ''branch'' de origem e quais ''branches'' devem ser considerados seu destino para receber o seu conteúdo por ''merge''. | Cada um desses ramos têm um propósito específico e estão vinculados a regras restritas sobre quais ''branches'' podem ser seu ''branch'' de origem e quais ''branches'' devem ser considerados seu destino para receber o seu conteúdo por ''merge''. | ||
De nenhuma maneira estes ''branches'' são considerados especiais do ponto de vista técnico. Os seus tipos são classificados pela forma como os mesmos são utilizados. | De nenhuma maneira estes ''branches'' são considerados especiais do ponto de vista técnico. Os seus tipos são classificados pela forma como os mesmos são utilizados. | ||
− | + | ====''Feature branches''==== | |
+ | [[Arquivo:Featurebranch-develop.png|thumb|100px]] | ||
* Pode ser um ''branch'' a partir de: | * Pode ser um ''branch'' a partir de: | ||
** ''developer'' | ** ''developer'' | ||
Linha 43: | Linha 55: | ||
''Feaure branches'' normalmente existem apenas no ''developer'', nunca no ''origin''. | ''Feaure branches'' normalmente existem apenas no ''developer'', nunca no ''origin''. | ||
+ | |||
+ | =====Criando um ''feature branch''===== | ||
+ | Quando começar a trabalhar em uma nova ''feature'', ramifica-se à partir do ''develop bracnh:'' | ||
+ | |||
+ | <pre> | ||
+ | $ git checkout -b myfeature develop | ||
+ | Switched to a new branch "myfeature" | ||
+ | </pre> | ||
+ | |||
+ | =====Incorporando uma ''feature'' concluída no ''develop branch''===== | ||
+ | ''Features'' finalizadas devem ter seu ''merge'' realizado no ''branch develop'' para definitivamente serem incorporadas na próxima versão de ''release''. | ||
+ | |||
+ | <pre> | ||
+ | $ git checkout develop | ||
+ | Switched to branch develop | ||
+ | $ git merge --no-ff myfeature | ||
+ | Updating ea1b82a..05e9557 | ||
+ | (Summary of changes) | ||
+ | $ git branch -d myfeature | ||
+ | Deleted branch myfeature (was 05e9557). | ||
+ | $ git push origin develop | ||
+ | </pre> | ||
+ | |||
+ | A flag <code> --no-ff </code> faz com que o processo de ''merge'' sempre crie um novo ''commit object'', mesmo que o ''merge'' pudesse ser feito no modelo ''fast-forward''. Isso evita a perda de informações sobre a existência histórica de um ''feature branch'' e agrupa todos os ''commits'' que, juntos, criam a nova ''feature''. Compare: | ||
+ | |||
+ | [[Arquivo:Merge-feature-develop.png|100px]] | ||
+ | |||
+ | No caso da direita, é impossível ver o histórico de ''commits objects'' que juntos implementaram a nova ''feature'', você teria que manualmente ler todas as mensagens de ''commits''. Neste caso, reverter a implementação de uma "feature" (grupo de ''commits'') é uma verdadeira dor de cabeça, contudo, torna-se muito simples quando a ''flag'' <code> --no-ff </code> é usada. | ||
+ | Sim, isto vai criar alguns ''commits objects'' vazios, mas o ganho é muito superior a este detalhe. | ||
+ | |||
+ | ====''Release branch''==== | ||
+ | * Pode ser ''brach'' de: | ||
+ | ** ''develop'' | ||
+ | * Deve ser feito ''merge'' em: | ||
+ | ** ''develop'' e ''master'' | ||
+ | * Convenção de nomenclatura para o ''branch'': | ||
+ | ** ''release''-* | ||
+ | |||
+ | ''Release branches'' apoiam a preparação de uma nova versão de produção. Eles permitem última hora pontilhando de eus e cruzamento t de. Além disso, eles permitem pequenas correções de bugs e a preparando dos meta-dados para um release (número da versão, data do ''build'', etc.). Ao fazer todo esse trabalho em um ''release branch'', o ''develop branch'' é apagado para receber as ''features'' para o próximo grande lançamento. | ||
+ | |||
+ | O momento adequado para criar um novo ''release branch'' à partir do ''develop'' é quando o ''branch develop'' (quase) reflete o estado desejado do novo ''release''. Pelo menos todos as ''features'' que estão planejadas para a ''release-to-be-build'' devem ter seu ''merge'' realizado no ''develop'' neste momento. Todos as ''features'' destinadas aos futuros lançamentos não podem (devem esperar) até que o ''release branch'' seja ''branched off''. | ||
+ | |||
+ | É exatamente no início de um ''release branch'' que é atribuído um número de versão, não antes disso. Até aquele momento, o ''delelop branch'' reflete as mudanças para a "próxima ''release''", mas não está claro se essa "próxima ''release''" acabará por se tornar 0.3 ou 1.0, até que o ''release branch'' seja iniciado. Essa decisão é feita no início do ''release branch'' e é realizado de acordo com regras definidas no projeto. | ||
+ | |||
+ | =====Criando um ''release branch''===== | ||
+ | ''Release branches'' são criados a partir do ''develop branch''. Por exemplo, digamos que a versão 1.1.5 é a versão de produção atual e temos um grande lançamento chegando. O estado do ''develop'' está pronto para o "próximo ''release''" e foi decidido que esta vai se tornar a versão 1.2 (em vez de 1.1.6 ou 2.0). Assim, removemos o ''branch'' e damos ao ''release branch'' um nome que reflita o número da versão: | ||
+ | |||
+ | <pre> | ||
+ | $ git checkout -b release-1.2 develop | ||
+ | Switched to a new branch "release-1.2" | ||
+ | $ ./bump-version.sh 1.2 | ||
+ | Files modified successfully, version bumped to 1.2. | ||
+ | $ git commit -a -m "Bumped version number to 1.2" | ||
+ | [release-1.2 74d9424] Bumped version number to 1.2 | ||
+ | 1 files changed, 1 insertions(+), 1 deletions(-) | ||
+ | </pre> | ||
+ | |||
+ | Depois de criar um novo ''branch'' e mudar para ele, realiza-se um ''bump'' no número da versão. Aqui, ''bump-version.sh'' é um ''shell script'' fictício que muda alguns arquivos na cópia para refletir a nova versão (isto pode ser, obviamente, uma mudança manual). Em seguida, é realizado o ''commit'' do número da versão. | ||
+ | |||
+ | Este novo ''branch'' pode existir lá por um tempo, até que a ''release'' seja implementada definitivamente. Durante esse tempo, correções de bugs podem ser aplicadas neste ''branch'' (ao invés do ''developer branch''). '''Adicionar grandes novas características aqui é estritamente proibido'''. Essas novas características devem ter ''merges'' no ''develop'' e, portanto, esperar pelo próximo grande ''release''. | ||
+ | |||
+ | =====Concluindo o ''release branch''===== | ||
+ | Quando o estado do ''release branch'' está pronto para se tornar um ''release'' real, algumas ações precisam ser realizadas. Em primeiro lugar, o ''release branch'' deve ter ''merge'' realizado no ''master'' (uma vez que cada ''commit'' no ''master'' é um novo lançamento por definição, lembre-se disso). Em seguida, o ''commit'' no ''master'' deve ser marcado para uma futura referência à esta versão histórica. Finalmente, as alterações feitas no ''release branch'' precisam ser ''merged'' de volta para o ''develop'', para que os futuros lançamentos também contênham estas correções de bugs. | ||
+ | |||
+ | As duas primeiras etapas em git: | ||
+ | |||
+ | <pre> | ||
+ | $ git checkout master | ||
+ | Switched to branch 'master' | ||
+ | $ git merge --no-ff release-1.2 | ||
+ | Merge made by recursive. | ||
+ | (Summary of changes) | ||
+ | $ git tag -a 1.2 | ||
+ | </pre> | ||
+ | |||
+ | |||
+ | O ''release'' agora está pronto e marcado para futuras referências. | ||
+ | :Obs.: Você pode usar a opção -s ou -u <chave> para assinar com criptografia. | ||
+ | |||
+ | Para manter as alterações feitas no ''release branch'', precisamos realizar o ''merge'' de volta para o ''developer''. No git: | ||
+ | <pre> | ||
+ | $ git checkout develop | ||
+ | Switched to branch 'develop' | ||
+ | $ git merge --no-ff release-1.2 | ||
+ | Merge made by recursive. | ||
+ | (Summary of changes) | ||
+ | </pre> | ||
+ | |||
+ | Este passo pode muito bem levar a um conflito de ''merge'' (uma vez que mudaram o número da versão). Se assim for, corrija e submeta (''commit''). | ||
+ | |||
+ | Agora que está tudo pronto o ''release branch'' pode ser removido, uma vez que não é mais necessário: | ||
+ | <pre> | ||
+ | $ git branch -d release-1.2 | ||
+ | Deleted branch release-1.2 (was ff452fe). | ||
+ | </pre> | ||
+ | |||
+ | ====''Hotfix branch''==== | ||
+ | [[Arquivo:Hotfix-branches.png|thumb|200px]] | ||
+ | * Pode ser ''branch'' de: | ||
+ | ** ''master'' | ||
+ | * Deve ter seu ''merge'' realizado em: | ||
+ | ** ''develop'' e ''master'' | ||
+ | * Convenção de nomenclatura para o ''branch'': | ||
+ | ** hotfix-* | ||
+ | |||
+ | ''Hotfix branches'' são muito parecidos com os ''release branches'', pois eles também são destinados para uma nova versão de produção, embora não planejada. Eles surgem da necessidade de agir imediatamente após um estado indesejável de uma versão de produção. Quando um erro crítico em uma versão de produção deve ser resolvido imediatamente, um ''hotfix branch'' poderá ser ''branched off'' a partir da tag correspondente no ''master branch'' que marca a versão de produção. | ||
+ | |||
+ | A essência é que o trabalho dos membros da equipe (no ''develop branch'') pode continuar, enquanto outra pessoa está preparando uma solução rápida para corrigir o incidente em produção. | ||
+ | |||
+ | =====Criando um ''hotfix branch''===== | ||
+ | ''Hotfix bracnhes'' são criados à partir do ''master branch''. Por exemplo, vamos dizer que a versão 1.2 que está em produção tem causado problemas por conta de um ''bug'' crítico. Porém as alterações no ''develop branch'' ainda estão instáveis. Neste caso, devemos criar um ''hotfix branch'' e iniciar a correção do problema. | ||
+ | <pre> | ||
+ | $ git checkout -b hotfix-1.2.1 master | ||
+ | Switched to a new branch "hotfix-1.2.1" | ||
+ | $ ./bump-version.sh 1.2.1 | ||
+ | Files modified successfully, version bumped to 1.2.1. | ||
+ | $ git commit -a -m "Bumped version number to 1.2.1" | ||
+ | [hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1 | ||
+ | 1 files changed, 1 insertions(+), 1 deletions(-) | ||
+ | </pre> | ||
+ | :Não esqueça de realizar o ''bump'' no número da versão | ||
+ | |||
+ | Agora, corrija o ''bug'' e realize o ''commit'' em um ou mais ''commits'': | ||
+ | <pre> | ||
+ | $ git commit -m "Fixed severe production problem" | ||
+ | [hotfix-1.2.1 abbe5d6] Fixed severe production problem | ||
+ | 5 files changed, 32 insertions(+), 17 deletions(-) | ||
+ | </pre> | ||
+ | |||
+ | =====Finalizando um ''hotfix branch''===== | ||
+ | Quando concluído, o ''bugfix'' precisa ser ''merged'' para o ''master'', mas também deve ser ''merged'' para o ''develop'', para que assim resguardar que a nova versão já possua o ''bugfix'' também. Esta tarefa é bem similar à como os ''release branches'' são concluídos. | ||
+ | Primeiro, atualize o ''master'' e coloque a ''tag'' no ''release'': | ||
+ | <pre> | ||
+ | $ git checkout master | ||
+ | Switched to branch 'master' | ||
+ | $ git merge --no-ff hotfix-1.2.1 | ||
+ | Merge made by recursive. | ||
+ | (Summary of changes) | ||
+ | $ git tag -a 1.2.1 | ||
+ | </pre> | ||
+ | Em seguida, inclua o ''bugfix'' no ''develop'': | ||
+ | >pre> | ||
+ | $ git checkout develop | ||
+ | Switched to branch 'develop' | ||
+ | $ git merge --no-ff hotfix-1.2.1 | ||
+ | Merge made by recursive. | ||
+ | (Summary of changes) | ||
+ | </pre> | ||
+ | Existe uma exceção a esta regra que é '''quando um ''release branch'' ainda existir as alterações realizadas no ''hotfix branch'' precisam ser ''merged'' no ''release branch'' ao invés do ''develop'''''. Ao efetuar o ''merge'' do ''bugfix'' no ''release branch'' pode causar eventualmente um ''merge'' do ''bugfix'' no ''develop'' também, quando o ''release branch'' for concluído. | ||
+ | |||
+ | Finalmente, remova o ''branch'' temporário: | ||
+ | <pre> | ||
+ | $ git branch -d hotfix-1.2.1 | ||
+ | Deleted branch hotfix-1.2.1 (was abbe5d6). | ||
+ | </pre> |
Edição atual tal como às 20h28min de 2 de junho de 2016
O git mudou a forma com a qual os desenvolvedores pensam a respeito de merges e branches. No mundo de código centralizado, merges e branches sempre foram considerados assustadores (cuidados com os conflitos do merge) e algo que era feito apenas uma vez em um longo tempo. Porém com o git essas ações são extremamente baratas e simples, e são consideradas o cerne do dia-a-dia de trabalho, de verdade. Como uma consequência de sua simplicidade e natureza repetitiva, criar branches e merges não é algo que se deva ter medo. As ferramentas de versionamento dispõem de toda a assistência necessária para realizar as tarefas de criação de branches e merges. Mais informações sobre o git e ferramentas de controle de código podem ser facilmente encontradas na web.
Após essa breve introdução sobre a ferramenta, vamos entrar de cabeça no modelo de desenvolvimento. O modelo aqui apresentado é essencialmente nada mais que um conjunto de procedimentos que cada membro da equipe tem que seguir a fim de chegar a um processo de desenvolvimento de software gerenciado.
Descentralizado, mas centralizado
O modelo de repositório utilizado para o gerenciamento de branches considera que temos apenas um único, e verdadeiro, repositório central. Note que este repositório é apenas considerado central (pois como o git é uma ferramenta de controle descentralizado, não existe um repositório central a nível técnico). Vamos nos referir a este repositório principal como origin, pois é um nome familiar a todos os usuários do git.
Cada desenvolvedor efetua pull e pushes no origin. Mas, além dessa relação centralizada comum, cada desenvolvedor deve também efetuar um pull das modificações realizadas por outros desenvolvedores de outras equipes. Por exemplo, isto pode ser útil quando um ou mais desenvolvedores estão trabalhando em uma nova grande funcionalidade, antes de enviar as alterações em progresso diretamente para o repositório origin prematuramente. Na figura ao lado, existem equipes de Alice e Bob, Alice e David, e Clair e David. Tecnicamente isto significa nada mais que Alice definiu um git remote (chamado bob) apontando para o repositório da equipe de Bob, e vice-versa.
O branch principal
No núcleo, o padrão de desenvolvimento é muito inspirado por modelos existentes no mercado. O repositório central detém dois branches principais, com uma vida útil infinita:
- master
- develop
O brach master no origin deve ser familiar para todo usuário git. Paralelamente ao branch master outro branch existe, chamado develop. Consideraremos o origin/master como main branch, onde o seu conteúdo sempre reflete o status de pronto para produção. Consideraremos o origin/develop como o principal branch onde o código fonte sempre reflete um estado com as mudanças de desenvolvimento mais recente entregues para a próxima sprint. Podemos chama-lo também de integration branch. É neste branch onde qualquer rotina noturna automática de build é executada. Quando o código-fonte no develop branch chega a um ponto estável e está pronto para ser lançado todas as alterações devem sofrer o merge com o branch master de alguma forma e, em seguida, ser marcado com um número de versão. Como isto é feito em detalhes será discutido mais adiante.
Portanto, cada vez que as alterações são mescladas de volta para o master', esta é uma nova versão de produção por definição. Devemos ser muito rigorosos com isso, de modo que, teoricamente, nós poderíamos usar um script automático para realizar o deploy e roll-out de nosso software para os nossos servidores de produção automaticamente toda vez que houve uma consolidação no master.
Os branches de suporte
Ao lado do master e develop branches, o nosso modelo de desenvolvimento utiliza uma variedade de branches de apoio para auxiliar o desenvolvimento paralelo entre os membros da equipe, facilitando o rastreamento de recursos, o preparo para versões de produção e para auxiliar na solução rápida de problemas na produção. Ao contrário dos branches principais, estes sempre tem um tempo de vida limitado, uma vez que eles serão removidos eventualmente. Os diferentes tipos de branches que podemos utilizar são:
- Feature branches
- Release branches
- Hotfix branches
Cada um desses ramos têm um propósito específico e estão vinculados a regras restritas sobre quais branches podem ser seu branch de origem e quais branches devem ser considerados seu destino para receber o seu conteúdo por merge.
De nenhuma maneira estes branches são considerados especiais do ponto de vista técnico. Os seus tipos são classificados pela forma como os mesmos são utilizados.
Feature branches
- Pode ser um branch a partir de:
- developer
- Deve ser feito 'merge de volta para:
- developer
- Convenção de nomenclatura para o branch:
- qualquer coisa, exceto master, developer, release-*, ou hotfix-*
Feature branches (às vezes chamados de topic branches) são usados para desenvolver novas funcionalidades para a próxima spirnt ou um lançamento futuro. Ao iniciar o desenvolvimento de uma feature, a versão alvo na qual esse recurso será incorporado pode muito bem ser desconhecida até esse ponto. A essência de um feature branch é que ele existe enquanto a feature está em desenvolvimento, a qual eventualmente acabará por ser feito o merge de volta para o develop (para adicionar definitivamente a nova feature na versão de release) ou descartados (no caso de uma experiência decepcionante).
Feaure branches normalmente existem apenas no developer, nunca no origin.
Criando um feature branch
Quando começar a trabalhar em uma nova feature, ramifica-se à partir do develop bracnh:
$ git checkout -b myfeature develop Switched to a new branch "myfeature"
Incorporando uma feature concluída no develop branch
Features finalizadas devem ter seu merge realizado no branch develop para definitivamente serem incorporadas na próxima versão de release.
$ git checkout develop Switched to branch develop $ git merge --no-ff myfeature Updating ea1b82a..05e9557 (Summary of changes) $ git branch -d myfeature Deleted branch myfeature (was 05e9557). $ git push origin develop
A flag --no-ff
faz com que o processo de merge sempre crie um novo commit object, mesmo que o merge pudesse ser feito no modelo fast-forward. Isso evita a perda de informações sobre a existência histórica de um feature branch e agrupa todos os commits que, juntos, criam a nova feature. Compare:
No caso da direita, é impossível ver o histórico de commits objects que juntos implementaram a nova feature, você teria que manualmente ler todas as mensagens de commits. Neste caso, reverter a implementação de uma "feature" (grupo de commits) é uma verdadeira dor de cabeça, contudo, torna-se muito simples quando a flag --no-ff
é usada.
Sim, isto vai criar alguns commits objects vazios, mas o ganho é muito superior a este detalhe.
Release branch
- Pode ser brach de:
- develop
- Deve ser feito merge em:
- develop e master
- Convenção de nomenclatura para o branch:
- release-*
Release branches apoiam a preparação de uma nova versão de produção. Eles permitem última hora pontilhando de eus e cruzamento t de. Além disso, eles permitem pequenas correções de bugs e a preparando dos meta-dados para um release (número da versão, data do build, etc.). Ao fazer todo esse trabalho em um release branch, o develop branch é apagado para receber as features para o próximo grande lançamento.
O momento adequado para criar um novo release branch à partir do develop é quando o branch develop (quase) reflete o estado desejado do novo release. Pelo menos todos as features que estão planejadas para a release-to-be-build devem ter seu merge realizado no develop neste momento. Todos as features destinadas aos futuros lançamentos não podem (devem esperar) até que o release branch seja branched off.
É exatamente no início de um release branch que é atribuído um número de versão, não antes disso. Até aquele momento, o delelop branch reflete as mudanças para a "próxima release", mas não está claro se essa "próxima release" acabará por se tornar 0.3 ou 1.0, até que o release branch seja iniciado. Essa decisão é feita no início do release branch e é realizado de acordo com regras definidas no projeto.
Criando um release branch
Release branches são criados a partir do develop branch. Por exemplo, digamos que a versão 1.1.5 é a versão de produção atual e temos um grande lançamento chegando. O estado do develop está pronto para o "próximo release" e foi decidido que esta vai se tornar a versão 1.2 (em vez de 1.1.6 ou 2.0). Assim, removemos o branch e damos ao release branch um nome que reflita o número da versão:
$ git checkout -b release-1.2 develop Switched to a new branch "release-1.2" $ ./bump-version.sh 1.2 Files modified successfully, version bumped to 1.2. $ git commit -a -m "Bumped version number to 1.2" [release-1.2 74d9424] Bumped version number to 1.2 1 files changed, 1 insertions(+), 1 deletions(-)
Depois de criar um novo branch e mudar para ele, realiza-se um bump no número da versão. Aqui, bump-version.sh é um shell script fictício que muda alguns arquivos na cópia para refletir a nova versão (isto pode ser, obviamente, uma mudança manual). Em seguida, é realizado o commit do número da versão.
Este novo branch pode existir lá por um tempo, até que a release seja implementada definitivamente. Durante esse tempo, correções de bugs podem ser aplicadas neste branch (ao invés do developer branch). Adicionar grandes novas características aqui é estritamente proibido. Essas novas características devem ter merges no develop e, portanto, esperar pelo próximo grande release.
Concluindo o release branch
Quando o estado do release branch está pronto para se tornar um release real, algumas ações precisam ser realizadas. Em primeiro lugar, o release branch deve ter merge realizado no master (uma vez que cada commit no master é um novo lançamento por definição, lembre-se disso). Em seguida, o commit no master deve ser marcado para uma futura referência à esta versão histórica. Finalmente, as alterações feitas no release branch precisam ser merged de volta para o develop, para que os futuros lançamentos também contênham estas correções de bugs.
As duas primeiras etapas em git:
$ git checkout master Switched to branch 'master' $ git merge --no-ff release-1.2 Merge made by recursive. (Summary of changes) $ git tag -a 1.2
O release agora está pronto e marcado para futuras referências.
- Obs.: Você pode usar a opção -s ou -u <chave> para assinar com criptografia.
Para manter as alterações feitas no release branch, precisamos realizar o merge de volta para o developer. No git:
$ git checkout develop Switched to branch 'develop' $ git merge --no-ff release-1.2 Merge made by recursive. (Summary of changes)
Este passo pode muito bem levar a um conflito de merge (uma vez que mudaram o número da versão). Se assim for, corrija e submeta (commit).
Agora que está tudo pronto o release branch pode ser removido, uma vez que não é mais necessário:
$ git branch -d release-1.2 Deleted branch release-1.2 (was ff452fe).
Hotfix branch
- Pode ser branch de:
- master
- Deve ter seu merge realizado em:
- develop e master
- Convenção de nomenclatura para o branch:
- hotfix-*
Hotfix branches são muito parecidos com os release branches, pois eles também são destinados para uma nova versão de produção, embora não planejada. Eles surgem da necessidade de agir imediatamente após um estado indesejável de uma versão de produção. Quando um erro crítico em uma versão de produção deve ser resolvido imediatamente, um hotfix branch poderá ser branched off a partir da tag correspondente no master branch que marca a versão de produção.
A essência é que o trabalho dos membros da equipe (no develop branch) pode continuar, enquanto outra pessoa está preparando uma solução rápida para corrigir o incidente em produção.
Criando um hotfix branch
Hotfix bracnhes são criados à partir do master branch. Por exemplo, vamos dizer que a versão 1.2 que está em produção tem causado problemas por conta de um bug crítico. Porém as alterações no develop branch ainda estão instáveis. Neste caso, devemos criar um hotfix branch e iniciar a correção do problema.
$ git checkout -b hotfix-1.2.1 master Switched to a new branch "hotfix-1.2.1" $ ./bump-version.sh 1.2.1 Files modified successfully, version bumped to 1.2.1. $ git commit -a -m "Bumped version number to 1.2.1" [hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1 1 files changed, 1 insertions(+), 1 deletions(-)
- Não esqueça de realizar o bump no número da versão
Agora, corrija o bug e realize o commit em um ou mais commits:
$ git commit -m "Fixed severe production problem" [hotfix-1.2.1 abbe5d6] Fixed severe production problem 5 files changed, 32 insertions(+), 17 deletions(-)
Finalizando um hotfix branch
Quando concluído, o bugfix precisa ser merged para o master, mas também deve ser merged para o develop, para que assim resguardar que a nova versão já possua o bugfix também. Esta tarefa é bem similar à como os release branches são concluídos. Primeiro, atualize o master e coloque a tag no release:
$ git checkout master Switched to branch 'master' $ git merge --no-ff hotfix-1.2.1 Merge made by recursive. (Summary of changes) $ git tag -a 1.2.1
Em seguida, inclua o bugfix no develop: >pre> $ git checkout develop Switched to branch 'develop' $ git merge --no-ff hotfix-1.2.1 Merge made by recursive. (Summary of changes) </pre> Existe uma exceção a esta regra que é quando um release branch ainda existir as alterações realizadas no hotfix branch precisam ser merged no release branch ao invés do develop. Ao efetuar o merge do bugfix no release branch pode causar eventualmente um merge do bugfix no develop também, quando o release branch for concluído.
Finalmente, remova o branch temporário:
$ git branch -d hotfix-1.2.1 Deleted branch hotfix-1.2.1 (was abbe5d6).