Thursday 19 April 2018

Práticas recomendadas para a estratégia de ramificação do subversion


Práticas recomendadas para estratégias de ramificação de subversão
Esta documentação foi escrita para descrever a série 1.7.x do Apacheв "ў Subversion®. Se você estiver executando uma versão diferente do Subversion, você é fortemente encorajado a visitar o svnbook / e, em vez disso, consultar a versão desta documentação apropriada para sua versão do Subversion.
Padrões de ramificação comuns.
Há muitos usos diferentes para ramificação e svn mesclar, e esta seção descreve o mais comum.
O controle de versão é usado com mais freqüência para o desenvolvimento de software, então é uma rápida olhada em dois dos padrões de ramificação / fusão mais comuns usados ​​por equipes de programadores. Se você não estiver usando o Subversion para desenvolvimento de software, sinta-se à vontade para ignorar esta seção. Se você é um desenvolvedor de software que usa o controle de versão pela primeira vez, preste muita atenção, pois esses padrões geralmente são considerados práticas recomendadas por pessoas experientes. Esses processos não são específicos do Subversion; eles são aplicáveis ​​a qualquer sistema de controle de versão. Ainda assim, pode ajudar a vê-los descritos nos termos do Subversion.
Liberar filiais.
A maioria dos programas tem um ciclo de vida típico: código, teste, lançamento, repetição. Existem dois problemas com este processo. Primeiro, os desenvolvedores precisam continuar escrevendo novos recursos, enquanto as equipes de garantia de qualidade levam tempo para testar versões supostamente estáveis ​​do software. O novo trabalho não pode parar enquanto o software é testado. Em segundo lugar, o time quase sempre precisa suportar versões de software mais antigas e lançadas; Se um bug for descoberto no código mais recente, é mais provável que exista também nas versões lançadas, e os clientes desejarão obter essa correção de bug sem ter que esperar por uma nova versão importante.
Aqui é onde o controle de versão pode ajudar. O procedimento típico parece assim:
Os desenvolvedores comprometem todo o trabalho novo no tronco. As mudanças do dia-a-dia estão comprometidas com / tronco: novos recursos, correções de bugs, e assim por diante.
O tronco é copiado para um ramo de "liberação". Quando a equipe acha que o software está pronto para ser lançado (digamos, uma versão 1.0), o / trunk pode ser copiado para /branches/1.0.
As equipes continuam a trabalhar em paralelo. Uma equipe inicia testes rigorosos do ramo de lançamento, enquanto outra equipe continua um novo trabalho (digamos, para a versão 2.0) em / trunk. Se os erros forem descobertos em qualquer local, as correções serão carregadas para frente e para trás, conforme necessário. Em algum momento, no entanto, mesmo esse processo pára. O ramo está "congelado" para o teste final antes de um lançamento.
O ramo é marcado e liberado. Quando o teste estiver concluído, /branches/1.0 é copiado para /tags/1.0.0 como um instantâneo de referência. A etiqueta é empacotada e lançada para clientes.
A filial é mantida ao longo do tempo. Enquanto o trabalho continua em / trunk para a versão 2.0, correções de bugs continuam sendo portadas de / trunk para /branches/1.0. Quando suficientes correções de bugs se acumulam, o gerenciamento pode decidir fazer uma versão 1.0.1: /branches/1.0 é copiado para /tags/1.0.1 e a etiqueta é empacotada e liberada.
Todo esse processo se repete à medida que o software amadurece: quando o trabalho 2.0 estiver completo, um novo ramo de liberação 2.0 é criado, testado, etiquetado e eventualmente lançado. Depois de alguns anos, o repositório termina com um número de ramificações de release em "manutenção" e várias tags representando as versões finais enviadas.
Ramos de recursos.
Um ramo de recursos é o tipo de ramo que tem sido o exemplo dominante neste capítulo (aquele em que você trabalhou enquanto a Sally continua trabalhando no tronco). É um ramo temporário criado para trabalhar em uma mudança complexa sem interferir com a estabilidade do tronco. Ao contrário dos ramos de lançamento (que podem precisar ser suportados para sempre), os ramos de recursos nascem, usados ​​por um tempo, fundidos de volta ao tronco e, em seguida, excluídos. Eles têm um período finito de utilidade.
Novamente, as políticas de projetos variam amplamente sobre exatamente quando é apropriado criar um ramo de recursos. Alguns projetos nunca usam ramos de recursos: os compromissos para / tronco são gratuitos para todos. A vantagem desse sistema é que é simples: "ninguém precisa aprender sobre ramificação ou fusão. A desvantagem é que o código do tronco é muitas vezes instável ou inutilizável. Outros projetos usam ramos para um extremo: nenhuma mudança já foi comprometida com o tronco diretamente. Até mesmo as mudanças mais triviais são criadas em uma ramificação de curta duração, cuidadosamente revisadas e mescladas ao tronco. Em seguida, a ramificação é excluída. Este sistema garante um tronco excepcionalmente estável e utilizável em todos os momentos, mas ao custo de sobrecarga de processo tremenda.
A maioria dos projetos utiliza uma abordagem intermediária. Eles geralmente insistem em que / compilar tronco e passar testes de regressão em todos os momentos. Um ramo de recursos é necessário apenas quando uma mudança requer um grande número de compromissos desestabilizadores. Uma boa regra geral é fazer esta pergunta: se o desenvolvedor trabalhou por dias isoladamente e depois comprometeu a grande mudança de uma só vez (de modo que o tronco nunca foi desestabilizado), seria uma grande mudança para revisão? Se a resposta a essa pergunta for sim, a mudança deve ser desenvolvida em um ramo de recurso. À medida que o desenvolvedor compromete mudanças incrementais no ramo, eles podem ser facilmente revisados ​​por colegas.
Finalmente, há a questão de como manter um ramo de recursos em sincronia com o tronco à medida que o trabalho avança. Como mencionamos anteriormente, há um grande risco de trabalhar em uma filial por semanas ou meses; as trocas de tronco podem continuar a chegar, até o ponto em que as duas linhas de desenvolvimento diferem tanto que pode se tornar um pesadelo tentar mesclar o ramo de volta ao tronco.
Esta situação é melhor evitada através da fusão regular das mudanças no tronco para o ramo. Elimine uma política: uma vez por semana, combine o valor da semana passada de alterações no tronco para o ramo.
Quando você finalmente estiver pronto para mesclar o ramo de características sincronizadas do tronco, comece fazendo uma fusão final das últimas mudanças no tronco para o ramo. Quando isso for feito, as versões mais recentes do ramo e do tronco são absolutamente idênticas, exceto para as mudanças de sua filial. Em seguida, você combina novamente com a opção --reintegrar:
Outra maneira de pensar sobre esse padrão é que sua sincronização semanal do tronco para o ramo é análoga à execução da atualização do svn em uma cópia de trabalho, enquanto a etapa de mesclagem final é análoga à execução do commit do svn a partir de uma cópia de trabalho. Afinal, o que mais é uma cópia de trabalho, mas um ramo privado muito superficial? É um ramo que é capaz de armazenar apenas uma mudança por vez.
Você está lendo Controle de Versão com o Subversion (para o Subversion 1.7), por Ben Collins-Sussman, Brian W. Fitzpatrick e C. Michael Pilato.

Práticas recomendadas para estratégias de ramificação de subversão
Obter através da App Store Leia esta publicação em nosso aplicativo!
Melhor estratégia de ramificação ao fazer integração contínua?
Qual é a melhor estratégia de ramificação a ser usada quando você quer fazer integração contínua?
Release Branching: desenvolva no tronco, mantenha um ramo para cada lançamento. Ramificação de recursos: desenvolva cada recurso em uma ramificação separada, apenas funde uma vez estável.
Faz sentido usar essas duas estratégias juntas? Como em, você se ramifica para cada versão, mas você também se ramifica para grandes recursos? Uma dessas estratégias engrena melhor com a integração contínua? Usar integração contínua ainda faz sentido ao usar um tronco instável?
11 Respostas.
A resposta depende do tamanho da equipe e da qualidade do controle de origem e da capacidade de mesclar conjuntos de mudanças complexos corretamente. Por exemplo, no controle de fonte de ramo completo, como a fusão CVS ou SVN pode ser difícil e você pode estar melhor com o primeiro modelo, enquanto que se usar um sistema mais complexo como o IBM ClearCase e com um tamanho maior de equipe, você poderia ser melhor com o segundo modelo ou uma combinação dos dois.
Eu pessoalmente separaria o modelo de ramificação de feições, onde cada característica principal é desenvolvida em uma ramificação separada, com sub-ramificações de tarefas para cada modificação feita pelo desenvolvedor individual. À medida que os recursos se estabilizam, eles são mesclados ao tronco, que você mantém razoavelmente estável e passando em todos os testes de regressão o tempo todo. À medida que você está perto do final do seu ciclo de lançamento e todos os ramos de recursos se fundem, você se estabiliza e se ramifica de um ramo do sistema de liberação no qual você apenas faz correções de bug de estabilidade e backports necessários, enquanto o tronco é usado para o desenvolvimento da próxima versão e você novamente se ramificam para novos ramos de recursos. E assim por diante.
Desta forma, o tronco contém sempre o código mais recente, mas você consegue mantê-lo razoavelmente estável, criando rótulos estáveis ​​(tags) em grandes mudanças e fusões de recursos, os ramos de recursos são desenvolvimento de ritmo rápido com integração contínua e sub-ramos de tarefas individuais podem ser muitas vezes atualizado do ramo de recursos para manter todos trabalhando no mesmo recurso em sincronia, sem afetar outras equipes que trabalham em diferentes recursos.
Ao mesmo tempo, você tem através do histórico um conjunto de ramos de lançamento, onde você pode fornecer backports, suporte e correções de erros para seus clientes que, por qualquer motivo, permanecem em versões anteriores do seu produto ou mesmo apenas na versão mais recente lançada. Tal como acontece com o tronco, você não configura a integração contínua nos ramos de lançamento, eles são cuidadosamente integrados ao passarem por todos os testes de regressão e outro controle de qualidade do release.
Se por algum motivo dois recursos são co-dependentes e precisam de mudanças feitas um com o outro, você pode considerar desenvolver ambos no mesmo ramo de recursos ou exigir que os recursos agrupem regularmente partes estáveis ​​do código no tronco e depois atualize as alterações de tronco para trocar código entre ramos do tronco. Ou, se você precisar isolar esses dois recursos de outras pessoas, poderá criar uma ramificação comum na qual ramificará essas ramificações de recurso e poderá usá-la para trocar códigos entre os recursos.
O modelo acima não faz muito sentido com equipes com menos de 50 desenvolvedores e sistema de controle de fonte sem ramos esparsos e capacidade de fusão adequada como CVS ou SVN, o que tornaria todo esse modelo um pesadelo para configurar, gerenciar e integrar.
Eu acho o tópico realmente interessante, porque eu confio muito nas filiais no meu trabalho diário.
Lembro-me de Mark Shuttleworth, que propõe um modelo sobre manter o ramo principal puro enquanto vai além do CI convencional. Eu postei sobre isso aqui. Como estou familiarizado com o Cruise Control, também bloguei sobre filiais de tarefas e CI aqui. É um tutorial passo a passo explicando como fazer isso com o Plastic SCM. Finalmente, encontrei alguns dos tópicos sobre CI (e potencialmente falando sobre ramificação) no livro de Duvall sobre CI muito interessante também.
Espero que você ache os links interessantes.
Eu pessoalmente acho muito mais limpo ter um tronco estável e apresentar ramificações. Dessa forma, os testadores e afins ficam em uma única "versão" e atualizam a partir do tronco para testar qualquer recurso que seja um código completo.
Além disso, se vários desenvolvedores estiverem trabalhando em recursos diferentes, eles podem ter seus próprios ramos separados, depois fundir no tronco quando terminarem e enviar um recurso para serem testados sem que o testador tenha que alternar para vários ramos para testar diferentes recursos.
Como um bônus adicional, há algum nível de testes de integração que vem automaticamente.
Eu acho que qualquer estratégia pode ser usada com desenvolvimento contínuo, desde que você se lembre de um dos princípios-chave que cada desenvolvedor compromete com o trunk / mainline todos os dias.
Eu tenho feito algumas leituras deste livro sobre CI e os autores sugerem que a ramificação por lançamento é a estratégia de ramificação preferida. Eu tenho que concordar. A ramificação por recurso não faz sentido para mim ao usar o IC.
Vou tentar e explicar por que estou pensando dessa maneira. Diga que três desenvolvedores pegam uma filial para trabalhar em um recurso. Cada recurso levará vários dias ou semanas para terminar. Para garantir que a equipe esteja se integrando continuamente, eles devem se comprometer com a filial principal pelo menos uma vez por dia. Assim que eles começam a fazer isso, eles perdem o benefício de criar um ramo de recursos. Suas mudanças não são mais separadas de todas as mudanças do outro desenvolvedor. Sendo assim, por que se preocupar em criar filiais de recursos em primeiro lugar?
Usar a ramificação por release requer muito menos mesclagem entre filiais (sempre uma coisa boa), garante que todas as alterações sejam integradas o mais rápido possível e (se feito corretamente) garante que sua base de código esteja sempre pronta para ser liberada. O lado negativo para se ramificar pelo lançamento é que você deve ter um cuidado consideravelmente mais cuidadoso com as mudanças. Por exemplo. A refatoração grande deve ser feita de forma incremental e, se você já integrou um novo recurso que não deseja na próxima versão, ele deve ser oculto usando algum tipo de mecanismo de alternância de recursos.
Há mais de uma opinião sobre este assunto. Aqui está uma postagem de blog que é uma ramificação de recursos pro com CI.
Os ramos de lançamento são muito úteis, e até mesmo absolutamente necessários, se você precisar manter várias versões do seu aplicativo.
As ramificações de recursos também são muito convenientes, especialmente se um desenvolvedor precisar trabalhar em uma grande alteração, enquanto outras ainda lançam novas versões.
Então, para mim, usar ambos os mecanismos é uma estratégia muito boa.
Link interessante do Livro do SVN.
Recentemente, gostei desse modelo ao usar o git. Embora sua pergunta seja marcada como "svn", você ainda pode fazer algum uso disso.
A integração contínua pode, em certa medida, acontecer no ramo "desenvolver" (ou seja o que for que você chamar) neste modelo, embora possuir ramos de recursos longos para lançamentos futuros não o tornem tão rígido quanto a considerar cada mudança acontecendo com o código em algum lugar. A questão permanece, se você realmente quer isso. Martin Fowler faz.
A integração contínua não deve ser qualquer tipo de fator na determinação de sua estratégia de ramificação. Sua abordagem de ramificação deve ser selecionada com base em sua equipe, o sistema em desenvolvimento e as ferramentas disponíveis para você.
Tendo dito isto .
não há nenhuma razão para que a CI não possa ser usada em ambas as abordagens que você descreve, essas abordagens funcionam bastante bem em combinação, nenhum dos dois trabalha "melhor" do que o outro CI faz todo o sentido com um tronco instável.
Tudo isso foi respondido na quarta pergunta na página que você pegou os diagramas de: blogs. collab / subversion / 2007/11 / branching-strat /
Enquanto você entender os princípios, você sempre pode reinventar as melhores práticas. Se você não entender os princípios, as melhores práticas irão levá-lo até antes de desmoronar devido a algum requisito externo conflitante.
Leia o link. Uma vez que você obteve o básico, leia o seguinte artigo pelo venerável Henrik Kniberg. Ele irá ajudá-lo a relacionar o Mainline Model com integração contínua.
Quando começamos nossa equipe, herdamos uma estratégia baseada no release do fornecedor que originalmente desenvolveu o sistema que estávamos prestes a assumir. Funcionou até o momento em que nossos clientes solicitaram que vários recursos desenvolvidos não fossem incluídos em uma versão (f. y.i.
250k linhas de código,
2500 arquivos, Scrum com XP SDLC).
Então começamos a olhar para os ramos baseados em funcionalidades. Isso também funcionou por um tempo - como 2 meses até o momento em que percebemos que nosso processo de teste de regressão levaria mais de 2 semanas, o que combinado com a incerteza do que seria lançado criou uma enorme inconveniência.
O último "prego no caixão" de estratégias SC puras veio quando decidimos que deveríamos ter 1. tronco estável e 2. A produção deveria conter BINÁRIOS testados ST, UAT e Regressão (não apenas fonte - pense CC).
Isso nos leva a conceber uma estratégia que seja um híbrido entre as estratégias SC e baseadas em lançamento.
Então nós temos um baú. Todos os sprints nos ramificamos no ramo de sprint (para pessoas não ágeis - um sprint é apenas um esforço de desenvolvimento com caixa de tempo com saída variável com base na complexidade). Do ramo de sprint criamos os ramos de recursos e o desenvolvimento paralelo é iniciado neles. Depois que os recursos são concluídos e testados pelo sistema, e recebemos a intenção de implantá-los, eles são mesclados à ramificação do sprint - alguns podem flutuar em vários sprints, geralmente os mais complexos. Uma vez que o sprint está perto do seu fim e as características estão completas. nós "renomeamos" o ramo de sprint para "regressão" (isso permite que o CruiseControl o apanhe sem qualquer reconfiguração) e o teste de regressão / integração começa no EAR construído no cc. Quando tudo estiver pronto, ele vai em produção.
Em suma, os ramos baseados em recursos são usados ​​para desenvolver, teste do sistema e funcionalidade UAT. O ramo de sprint (realmente o ramo de lançamento) é usado para mesclar seletivamente os recursos sob demanda e teste de integração.
Agora, aqui está uma pergunta para a comunidade - obviamente, estamos tendo problemas para realizar a integração contínua devido ao fato de que o desenvolvimento acontece em muitos ramos e na sobrecarga de reconfiguração do CruiseControl. Alguém pode sugerir e aconselhar?
Do jeito que eu vejo, você quer ter um conjunto limitado de ramificações onde você possa se concentrar. Como você deseja testes, métricas de qualidade de código e muitas coisas interessantes para executar com as compilações, ter muitos relatórios provavelmente fará você perder informações.
Quando e o que se ramifica, geralmente depende do tamanho da equipe e do tamanho das características que estão sendo desenvolvidas. Eu não acho que haja uma regra de ouro. Certifique-se de usar uma estratégia na qual você possa obter feedback com antecedência / frequência, e isso inclui ter a qualidade envolvida desde o início dos recursos. O bit de qualidade significa que, à medida que você está automatizando à medida que a equipe se desenvolve, se você se ramificar para um grande conjunto de recursos que uma equipe está construindo, você também precisa envolver a qualidade da equipe.
ps Onde você conseguiu essas referências de abordagem? - não acha que esses gráficos representam todas as opções.
Atualização 1: expandindo porque eu disse que não é uma regra de ouro. Basicamente, para equipes relativamente pequenas, achei melhor usar uma abordagem que é uma mistura. Os ramos de recursos são criados se for algo longo e parte da equipe continuará adicionando recursos menores.
Eu acho que as ferramentas que você usa são um grande fator aqui.
Se você estiver usando subversão, continue com a opção 1 e libere das ramificações. Se você estiver usando o GIT, a opção 2 funcionará bem para você.

Práticas recomendadas para estratégias de ramificação de subversão
Obter através da App Store Leia esta publicação em nosso aplicativo!
Escolhendo a estratégia de ramificação certa para lançamentos.
Começando com uma nova equipe de desenvolvimento em um novo projeto e devemos definir nossa estratégia de Ramificação para nosso repositório de fontes (por exemplo, Microsoft Team Foundation Server 2010). Nós nos deparamos com uma discussão sobre se ou não.
UMA . Tenha um ramo de liberação do qual fazemos compilações de produção e, em seguida, Label quando algo for realmente lançado.
B. Tenha um novo ramo Release para cada lançamento novo em produção (Ex. Versão 1, 2, 3, etc.)
A opção A parece bastante direta, mas não temos certeza se isso levará a problemas no longo prazo. A opção B parece que apenas cria muitos ramos únicos de longa duração que se acumulam ao longo do tempo.
Alguém tem alguma experiência que nos ajude a decidir? Especificamente, estou procurando saber onde estão os pontos problemáticos para qualquer escolha. Sinta-se à vontade para fornecer experiência específica relativa às implicações do TFS e / ou Release-Management.
Opção A. Apenas usando o mainline e a marcação para lançamento.
Você evita o inferno. Manter a linha principal incentiva algumas práticas recomendadas, como um planejamento de lançamento adequado, não introduzindo muitos WIP, usando ramificação por abstração para lidar com o trabalho a longo prazo fora de banda e usando o sistema fechado aberto e recursos configuráveis ​​para lidar com trabalhos de gerenciamento em andamento que pode; ou não pode; precisa ser desativado agora ou no futuro, a fim de liberar ou evitar uma reversão completa.
Lidar com trabalhos em andamento torna-se um problema e aumenta a área potencial de ataque de superfície quando chegar a hora de liberar. No entanto, se seus desenvolvedores forem disciplinados, os novos recursos deverão ser configuráveis ​​e modulares e, portanto, facilmente desabilitados / habilitados ou não haverá WIP e, em cada ponto de liberação, todo o trabalho será concluído ou ainda não foi iniciado (por exemplo, Scrum). As mudanças em grande escala / fora da banda requerem mais reflexão antes do tempo para implementar (por exemplo, ramificação por abstração).
Pessoalmente, eu prefiro essa abordagem. A cobertura do código e os testes unitários devem identificar o código que não está pronto para sair e as pessoas não devem trabalhar no código que não será divulgado durante a iteração atual. A ramificação por abstração ou outros mecanismos podem ser usados ​​para lidar com mudanças de longo prazo e trabalhos em andamento.
Quando você não faz isso, começa a se deparar com problemas de mesclagem, códigos obsoletos, recursos que nunca são lançados etc.
Opção B. Filial por lançamento.
Você pode começar a trabalhar na próxima iteração enquanto a iteração atual termina a rodada de testes de aceitação. Outras coisas, tenho certeza.
Toneladas de galhos. Ainda precisa marcar as ramificações nos pontos de liberação. Ainda precisa lidar com o WIP e mesclar o WIP da ramificação do release anterior para a próxima ramificação do release, se não for fazê-lo e ainda precisar desabilitá-lo da ramificação do release e executar novamente os testes de aceitação Os hot fixes precisam ser aplicados a mais ramificações (release branch + hotfix + new tag + misge hotfix em vnext branch e, possivelmente, vnextnext dependendo de onde o hotfix cai).
Eu não sou um grande fã dessa solução ^ _ ^.
Em geral, eu recomendaria apenas tentar manter a linha principal. Se os seus desenvolvedores estão tendo problemas para não escrever o WIP que pode ser facilmente arrancado quando ele falha no corte ou que é verificado no início do próximo lançamento, então você pode começar a falar sobre codificar o código no ponto em que deveria estar codificado e ramificado a partir daí, se necessário, abordar defeitos e erros ignorados que os testes da unidade de desenvolvedores não conseguiram capturar.
Idealmente, embora eu pense que você quer que seja o processo de exceção, não a regra.
Opção C. Opção de bônus louco.
Se você deseja ter fantasia, você também pode considerar um modelo de ramificação por usuário / história por recurso. (Uma idéia terrível em TFS ou qualquer não DVCS, ao mesmo tempo incrivelmente trivial para implementar se usar um DVCS como git ou mercurial).
No passado, implementei os itens abaixo para uma equipe anterior de manutenção de empregadores que trabalhou com uma base de código legado que não poderia ser facilmente transferida para o mercurial do svn. Muito trabalho desnecessário foi envolvido para atender a uma exigência de negócios de uma linha principal sempre liberável, em vez de apenas coordenar os lançamentos melhor, mas. . .
Os recursos foram desenvolvidos por desenvolvedores em seus desenvolvedores de equipes. Quando um recurso está pronto para ser revisado por pares, os desenvolvedores o agrupam em uma única mesclagem do ramo Dev no ramo CR e incluem a ID do recurso / história do usuário no título. * Aplicado pelo gancho pré-compromisso * Depois que ele passa CR, uma ferramenta de administração é usada para promover o recurso no ramo QA. (Escrevi um pequeno aplicativo de terminal que listou as histórias de usuários presentes nos vários estágios de aceitação e permitiu ao operador promovê-lo ou degradá-lo entre esses estágios de aceitação) O QA executa testes de automação e usabilidade manual. Se o recurso for bom, é empurrado para o ramo de liberação (linha principal). Se o recurso for rejeitado, ele será demolido / revertido para fora do ramo QA até que os desenvolvedores possam resolver os problemas levantados durante o teste e adicionar enviar um patch para o ramo CR. Se o código foi revertido da ramificação QA e uma correção for aplicada, a ferramenta de terminal reaplicará as alterações necessárias para trazer o recurso de volta à ramificação QA da ramificação CR para que a QA revise o código e promova-o ou rebaixá-lo novamente. Em qualquer momento, o ramo de liberação deve estar em um estado estável e solúvel. Após um novo lançamento Dev, QA e CR, são feitos a partir do mainline.
Temos ramificações separadas para cada lançamento que lançamos (aproximadamente 4 por ano). É muito conveniente quando você precisa puxar uma versão específica.
Se você precisa manter alguns lançamentos mais antigos, não acho que a rotulagem faria. Com ramos de liberação específicos, você pode aplicar hot-fixes a cada ramificação separadamente (ou a uma seleção deles) sem se preocupar com nenhum dos outros lançamentos.
Ele também faz comparações muito mais fáceis quando você procura quando um bug ou um recurso foi introduzido.
Não se preocupe com o número de filiais ou com o tempo que eles vão sem mudanças. Seu sistema de controle de versão é para fornecer controle e fornecer um histórico do desenvolvimento do seu projeto. A história tem tendência a não mudar. E não se preocupe com o fato de seus cvs não serem capazes de lidar. Usamos os arquivos Perforce, 9000+ em um ramo de desenvolvimento, até 50 ramos de desenvolvimento para o (s) lançamento (s) em que estamos trabalhando e como já dissemos, um único ramo por versão que publicamos. Perforce nem sequer respira mais.
Em suma: torne sua vida como desenvolvedor / mantenedor / bug-fixer / problem-hunter mais fácil e não se preocupe com o número de filiais ou o número de arquivos. Quaisquer cvs auto-respeitáveis ​​vão lidar.
Nós não sofremos nenhuma confusão em relação ao número de filiais que temos. Nosso esquema de nomeação para os ramos de lançamento e nossa 1 política de ramo do problema 1 para os ramos de desenvolvimento (ou trabalho) podem ter algo a ver com isso.
As ramificações de lançamento são nomeadas para o lançamento, ou seja: R2011SP1 para o Release 2011 Service Pack 1. Nossas ramificações de trabalho têm nomes menos inteligentes: sub01, sub02, sub03 etc. O "sub" vem do fato de que todos os ramos de trabalho são sub branch do ramo de aceitação. O ramo de aceitação é aquele em que todos os problemas são coletados e estão prontos para serem liberados.
Nossa política de ramo de trabalho de 1 problema 1, combinada com o fato de que nosso sistema de rastreamento de problemas foi personalizado com um campo de "ramificação" garante que sempre sabemos qual é o problema desenvolvido em qual ramo. Quando um problema é integrado ao ramo de aceitação, este campo é atualizado. Isso significa que sempre sabemos quais problemas estão prontos para serem liberados (assim que o teste de aceitação é feito). Da mesma forma, atualizamos esse campo quando um ramo de lançamento é criado e, dessa forma, sempre podemos rastrear em que lançamento um problema lançado.
É tudo sobre o contexto: com que frequência você libera e o que está em uma versão.
Aqui está um pouco de estudo de caso que eu tive com meu antigo trabalho, usando o método B (chamamos de ramo por propósito).
Para colocar a história no contexto,
Um lançamento consistiu em novos recursos em nosso software: novos modos de jogo, novas funcionalidades, novas opções de configuração. O ciclo de liberação foi bastante longo: nossos clientes eram universidades que ficariam com um conjunto de recursos por geralmente um ano.
O desenvolvimento principal foi feito no tronco até chegarmos a um estado completo de recursos para uma versão certa. Nesse ponto, criaríamos um ramo, digamos projectname-january2012 e fizemos nossos testes de qualidade e correções de bugs nesse mesmo ramo. Uma vez que estivéssemos prontos para uma versão pública, nós ostentaríamos o código nesse ramo e liberaríamos.
No entanto, o desenvolvimento na versão não acabou com essa tag. Inevitavelmente, tivemos clientes que encontraram erros ou pequenos problemas com o lançamento. Então, nesse caso, tudo o que precisamos fazer é voltar para esse ramo, corrigir o código e criar uma nova versão etiquetada do ramo de janeiro de 2012 para ser lançado e mesclar as correções de volta ao tronco.
No nosso caso, essa abordagem foi favorável porque alguns usuários preferiram ficar com lançamentos mais antigos com um conjunto limitado de recursos, ou simplesmente porque o custo de implantar em sua infraestrutura uma nova versão em vez de um hotfix causou alguns problemas.
Então, as perguntas que você precisa fazer são:
Quantas vezes eu libero? Os meus lançamentos serão 100% compatíveis com versões anteriores? Os meus clientes estarão bem com a atualização completa para corrigir erros?
Se você liberar com frequência, talvez não valha a pena ter sucursais para cada um deles. No entanto, se o seu ciclo de lançamento for razoavelmente longo como o meu antigo caso de uso, e essa implantação, compatibilidade com versões anteriores e clientes agarrados a versões antigas puderem ser riscos, a opção B certamente lhe poupará muita dor, facilitará muito o suporte seus clientes com o custo mínimo de lidar com a confusão dos ramos.
Eu prefiro a opção A. Desenvolva os lançamentos do tronco e do ramo quando estiverem estáveis. Isso limita significativamente o trabalho na integração de hot-aplages aplicadas à versão de produção.
Fui contratado para ajudar uma equipe que tentou a opção B a voltar aos trilhos.
Algumas coisas a considerar.
Migre hotfixes para a frente através de todos os ramos de código ativos. Isso pode ser feito por mesclagem, parcelamento e / ou reconstrução. Estes devem ser totalmente gerenciados para garantir que uma correção seja aplicada a todos os lançamentos apropriados e depois ao tronco. Considere ramos de recursos para permitir o desenvolvimento de recursos isolados do fluxo de código principal. Estes são recomendados para alterações experimentais. Sinta-se à vontade para abandonar ramos de recursos se o recurso não funcionar. Marcar e rastrear seus pontos de mesclagem. Junte seus lançamentos quando necessário. Eu acho que isso é normalmente quando a versão está pronta para lançar compilações de candidatos. Em alguns casos, a introdução de alterações incompatíveis no tronco pode forçar e ramificar rapidamente. Considere um ramo de características.
Trabalhei há alguns anos em um sistema que usa algo um pouco entre os dois esquemas que você descreve. A chave é que existe um esquema de numeração de vários níveis em uso. O nível externo é basicamente a versão da API, e isso é gerenciado em ramos (com fusões cruzadas apropriadas quando algo precisa ser consertado em vários ramos) e o nível interno é o lançamento exato feito, que é gerenciado com tags.
Em particular, se sabemos qual é a versão exata de um cliente, sabemos exatamente de que fonte o código foi construído e pode fazer uma duplicação exata para que possamos ver exatamente o que está acontecendo. Isso é muito importante para o apoio! No entanto, o nível externo dos ramos, as versões da API que lançamos atualmente, eles evoluem ao longo do tempo (com o tronco principal do desenvolvimento obtendo a maioria dos novos recursos). Além disso, quando fazemos uma nova versão importante da API, fazemos um novo ramo para suportar isso (de modo que o tronco pode sempre ser orientado para o desenvolvimento do hard-core) e consideramos se devemos terminar a vida o suporte mais antigo atual ramo.
Assim, eu recomendo algo que é realmente uma mistura de A e B; Ambos têm bons aspectos, mas nenhum deles é completo. Use o melhor dos dois mundos.
Eu usei o TFS para efetivamente implementar a opção (B) no passado.
Ramificação / fusão é uma ótima ferramenta quando é feito em pequenos pedaços. A dificuldade não está em fazer um branch (isso é estupidez), nem em empurrar uma semana de trabalho para cima da árvore (isso também é fácil). é fazer com que o sistema CI esteja atrás do seu controle de origem para trabalhar automaticamente para você.
Como a ramificação é desconfiada se o sistema não estiver construindo e executando automaticamente testes para o seu ramo.
Nós customizamos o fluxo de trabalho de construção padrão do TFS para reconhecer os caminhos relativos dos conjuntos de mudanças e estabelecemos uma convenção pela qual a customização poderia reconhecer um novo ramo (em oposição a simplesmente uma nova subpasta sob alguma raiz de desenvolvimento). Era suave, fácil de ramificar, fácil de matar um ramo, e recebemos feedback contínuo do nosso sistema para compilações e testes.
Eu vejo muitas pessoas declarando como essas estratégias são impossíveis sob o TFS, e acredito que seja devido à falta de familiaridade com as possibilidades de um mecanismo de criação baseado em XAML. O TFS não é apenas o controle de origem, é uma solução completa e deve ser usado como tal.

O recurso abre caminho para a grandeza.
Ou tarefa ramificando seu caminho até lá. Ou liberar ramificações. Você escolhe.
Quase todos os sistemas de controle de versão hoje oferecem suporte a ramos e ndash, linhas de trabalho independentes que decorrem de uma base de código central. Depending on your version control system, the main branch may be called master, mainline, default, or trunk. Developers can create their own branches from the main code line and work independently alongside it.
Why bother with branching?
Branching allows teams of developers to easily collaborate inside of one central code base. When a developer creates a branch, the version control system creates a copy of the code base at that point in time. Changes to the branch don't affect other developers on the team. This is a good thing, obviously, because features under development can create instability, which would be highly disruptive if all work was happening on the main code line. But branches need not live in solitary confinement. Developers can easily pull down changes from other developers to collaborate on features and ensure their private branch doesn’t diverge too far from the master.
Branches aren't just good for feature work. Branches can insulate the team from important architectural changes like updating frameworks, common libraries, etc.
Three branching strategies for agile teams.
Branching models often differ between teams, and are the subject of much debate in the software community. One big theme is how much work should remain in a branch before getting merged back into master.
Release branching.
Release branching refers to the idea that a release is contained entirely within a branch. This means that late in the development cycle, the release manager will create a branch from the master (e. g., “1.1 development branch”). All changes for the 1.1 release need to be applied twice: once to the 1.1 branch and then to the master code line. Working with two branches is extra work for the team and it's easy to forget to merge to both branches. Release branches can be unwieldy and hard to manage as many people are working on the same branch. We’ve all felt the pain of having to merge many different changes on one single branch. If you must do a release branch, create the branch as close to the actual release as possible.
Release branching is an important part of supporting versioned software out in the market. A single product may have several release branches (e. g., 1.1, 1.2, 2.0) to support sustaining development. Keep in mind that changes in earlier versions (i. e., 1.1) may need to be merged to later release branches (i. e., 1.2, 2.0). Check out our webinar below to learn more about managing release branches with Git.
Feature branching.
Feature branches are often coupled with feature flags–"toggles" that enable or disable a feature within the product. That makes it easy to deploy code into master and control when the feature is activated, making it easy to initially deploy the code well before the feature is exposed to end-users.
Another benefit of feature flags is that the code can remain within the build but inactive while it's in development. If something goes awry when the feature is enabled, a system admin can revert the feature flag and get back to a known good state rather than have to deploy a new build.
Task Branching.
At Atlassian, we focus on a branch-per-task workflow. Every organization has a natural way to break down work in individual tasks inside of an issue tracker, like Jira Software. Issues then becomes the team's central point of contact for that piece of work. Task branching, also known as issue branching, directly connects those issues with the source code. Each issue is implemented on its own branch with the issue key included in the branch name. It’s easy to see which code implements which issue: just look for the issue key in the branch name. With that level of transparency, it's easier to apply specific changes to master or any longer running legacy release branch.
Since agile centers around user stories, task branches pair well with agile development. Each user story (or bug fix) lives within its own branch, making it easy to see which issues are in progress and which are ready for release. For a deep-deep dive into task branching (sometimes called issue branching or branch-per-issue), grab some popcorn and check out the webinar recording below–one of our most popular ever.
Now meet branching's evil twin: the merge.
We’ve all endured the pain of trying to integrate multiple branches into one sensible solution. Traditionally, centralized version control systems like Subversion have made merging a very painful operation. But newer version control systems like Git and Mercurial take a different approach to tracking versions of files that live on different branches.
Branches tend to be short-lived, making them easier to merge and more flexible across the code base. Between the ability to frequently and automatically merge branches as part of continuous integration (CI), and the fact that short-lived branches simply contain fewer changes, "merge hell" becomes is a thing of the past for teams using Git and Mercurial.
That's what makes task branching so awesome!
Validate, validate, validate.
A version control system can only go so far in affecting the outcome of a merge. Automated testing and continuous integration are critical as well. Most CI servers can automatically put new branches under test, drastically reducing the number of "surprises" upon the final merge upstream and helping to keep the main code line stable.
Agile has had a huge impact on me both professionally and personally as I've learned the best experiences are agile, both in code and in life. You'll often find me at the intersection of technology, photography, and motorcycling. Find me on Twitter! danradigan.
Sign up for more articles.
Obrigado por inscrever-se!
How to do scrum with Jira Software.
A step-by-step guide on how to drive a scrum project, prioritize and organize your backlog into sprints, run the Scrum ceremonies and more, all within Jira Software.
Git branching for agile teams.
Moving to Git opens up a whole new level of agility for software teams. Here's how to design branching schemes for shipping both SaaS and installed products.

A successful Git branching model.
on Tuesday, January 05, 2010.
In this post I present the development model that I’ve introduced for some of my projects (both at work and private) about a year ago, and which has turned out to be very successful. I’ve been meaning to write about it for a while now, but I’ve never really found the time to do so thoroughly, until now. I won’t talk about any of the projects’ details, merely about the branching strategy and release management.
For a thorough discussion on the pros and cons of Git compared to centralized source code control systems, see the web. There are plenty of flame wars going on there. As a developer, I prefer Git above all other tools around today. Git really changed the way developers think of merging and branching. From the classic CVS/Subversion world I came from, merging/branching has always been considered a bit scary (“beware of merge conflicts, they bite you!”) and something you only do every once in a while.
But with Git, these actions are extremely cheap and simple, and they are considered one of the core parts of your daily workflow, really. For example, in CVS/Subversion books, branching and merging is first discussed in the later chapters (for advanced users), while in every Git book, it’s already covered in chapter 3 (basics).
As a consequence of its simplicity and repetitive nature, branching and merging are no longer something to be afraid of. Version control tools are supposed to assist in branching/merging more than anything else.
Enough about the tools, let’s head onto the development model. The model that I’m going to present here is essentially no more than a set of procedures that every team member has to follow in order to come to a managed software development process.
Decentralized but centralized ¶
The repository setup that we use and that works well with this branching model, is that with a central “truth” repo. Note that this repo is only considered to be the central one (since Git is a DVCS, there is no such thing as a central repo at a technical level). We will refer to this repo as origin , since this name is familiar to all Git users.
Each developer pulls and pushes to origin. But besides the centralized push-pull relationships, each developer may also pull changes from other peers to form sub teams. For example, this might be useful to work together with two or more developers on a big new feature, before pushing the work in progress to origin prematurely. In the figure above, there are subteams of Alice and Bob, Alice and David, and Clair and David.
Technically, this means nothing more than that Alice has defined a Git remote, named bob , pointing to Bob’s repository, and vice versa.
The main branches ¶
At the core, the development model is greatly inspired by existing models out there. The central repo holds two main branches with an infinite lifetime:
The master branch at origin should be familiar to every Git user. Parallel to the master branch, another branch exists called develop .
We consider origin/master to be the main branch where the source code of HEAD always reflects a production-ready state.
We consider origin/develop to be the main branch where the source code of HEAD always reflects a state with the latest delivered development changes for the next release. Some would call this the “integration branch”. This is where any automatic nightly builds are built from.
When the source code in the develop branch reaches a stable point and is ready to be released, all of the changes should be merged back into master somehow and then tagged with a release number. How this is done in detail will be discussed further on.
Therefore, each time when changes are merged back into master , this is a new production release by definition . We tend to be very strict at this, so that theoretically, we could use a Git hook script to automatically build and roll-out our software to our production servers everytime there was a commit on master .
Supporting branches ¶
Next to the main branches master and develop , our development model uses a variety of supporting branches to aid parallel development between team members, ease tracking of features, prepare for production releases and to assist in quickly fixing live production problems. Unlike the main branches, these branches always have a limited life time, since they will be removed eventually.
The different types of branches we may use are:
Each of these branches have a specific purpose and are bound to strict rules as to which branches may be their originating branch and which branches must be their merge targets. We will walk through them in a minute.
By no means are these branches “special” from a technical perspective. The branch types are categorized by how we use them. They are of course plain old Git branches.
Feature branches ¶
May branch off from: develop Must merge back into: develop Branch naming convention: anything except master , develop , release-* , or hotfix-*
Feature branches (or sometimes called topic branches) are used to develop new features for the upcoming or a distant future release. When starting development of a feature, the target release in which this feature will be incorporated may well be unknown at that point. The essence of a feature branch is that it exists as long as the feature is in development, but will eventually be merged back into develop (to definitely add the new feature to the upcoming release) or discarded (in case of a disappointing experiment).
Feature branches typically exist in developer repos only, not in origin .
Creating a feature branch ¶
When starting work on a new feature, branch off from the develop branch.
Incorporating a finished feature on develop ¶
Finished features may be merged into the develop branch to definitely add them to the upcoming release:
The --no-ff flag causes the merge to always create a new commit object, even if the merge could be performed with a fast-forward. This avoids losing information about the historical existence of a feature branch and groups together all commits that together added the feature. Comparar:
In the latter case, it is impossible to see from the Git history which of the commit objects together have implemented a feature—you would have to manually read all the log messages. Reverting a whole feature (i. e. a group of commits), is a true headache in the latter situation, whereas it is easily done if the --no-ff flag was used.
Yes, it will create a few more (empty) commit objects, but the gain is much bigger than the cost.
Release branches ¶
Release branches support preparation of a new production release. They allow for last-minute dotting of i’s and crossing t’s. Furthermore, they allow for minor bug fixes and preparing meta-data for a release (version number, build dates, etc.). By doing all of this work on a release branch, the develop branch is cleared to receive features for the next big release.
The key moment to branch off a new release branch from develop is when develop (almost) reflects the desired state of the new release. At least all features that are targeted for the release-to-be-built must be merged in to develop at this point in time. All features targeted at future releases may not—they must wait until after the release branch is branched off.
It is exactly at the start of a release branch that the upcoming release gets assigned a version number—not any earlier. Up until that moment, the develop branch reflected changes for the “next release”, but it is unclear whether that “next release” will eventually become 0.3 or 1.0, until the release branch is started. That decision is made on the start of the release branch and is carried out by the project’s rules on version number bumping.
Creating a release branch ¶
Release branches are created from the develop branch. For example, say version 1.1.5 is the current production release and we have a big release coming up. The state of develop is ready for the “next release” and we have decided that this will become version 1.2 (rather than 1.1.6 or 2.0). So we branch off and give the release branch a name reflecting the new version number:
After creating a new branch and switching to it, we bump the version number. Here, bump-version. sh is a fictional shell script that changes some files in the working copy to reflect the new version. (This can of course be a manual change—the point being that some files change.) Then, the bumped version number is committed.
This new branch may exist there for a while, until the release may be rolled out definitely. During that time, bug fixes may be applied in this branch (rather than on the develop branch). Adding large new features here is strictly prohibited. They must be merged into develop , and therefore, wait for the next big release.
Finishing a release branch ¶
When the state of the release branch is ready to become a real release, some actions need to be carried out. First, the release branch is merged into master (since every commit on master is a new release by definition , remember). Next, that commit on master must be tagged for easy future reference to this historical version. Finally, the changes made on the release branch need to be merged back into develop , so that future releases also contain these bug fixes.
The first two steps in Git:
The release is now done, and tagged for future reference.
Edit: You might as well want to use the - s or - u <key> flags to sign your tag cryptographically.
To keep the changes made in the release branch, we need to merge those back into develop , though. In Git:
This step may well lead to a merge conflict (probably even, since we have changed the version number). If so, fix it and commit.
Now we are really done and the release branch may be removed, since we don’t need it anymore:
Hotfix branches ¶
May branch off from: master Must merge back into: develop and master Branch naming convention: hotfix-*
Hotfix branches are very much like release branches in that they are also meant to prepare for a new production release, albeit unplanned. They arise from the necessity to act immediately upon an undesired state of a live production version. When a critical bug in a production version must be resolved immediately, a hotfix branch may be branched off from the corresponding tag on the master branch that marks the production version.
The essence is that work of team members (on the develop branch) can continue, while another person is preparing a quick production fix.
Creating the hotfix branch ¶
Hotfix branches are created from the master branch. For example, say version 1.2 is the current production release running live and causing troubles due to a severe bug. But changes on develop are yet unstable. We may then branch off a hotfix branch and start fixing the problem:
Don’t forget to bump the version number after branching off!
Then, fix the bug and commit the fix in one or more separate commits.
Finishing a hotfix branch.
When finished, the bugfix needs to be merged back into master , but also needs to be merged back into develop , in order to safeguard that the bugfix is included in the next release as well. This is completely similar to how release branches are finished.
First, update master and tag the release.
Edit: You might as well want to use the - s or - u <key> flags to sign your tag cryptographically.
Next, include the bugfix in develop , too:
The one exception to the rule here is that, when a release branch currently exists, the hotfix changes need to be merged into that release branch, instead of develop . Back-merging the bugfix into the release branch will eventually result in the bugfix being merged into develop too, when the release branch is finished. (If work in develop immediately requires this bugfix and cannot wait for the release branch to be finished, you may safely merge the bugfix into develop now already as well.)
Finally, remove the temporary branch:
While there is nothing really shocking new to this branching model, the “big picture” figure that this post began with has turned out to be tremendously useful in our projects. It forms an elegant mental model that is easy to comprehend and allows team members to develop a shared understanding of the branching and releasing processes.
A high-quality PDF version of the figure is provided here. Go ahead and hang it on the wall for quick reference at any time.
Update: And for anyone who requested it: here’s the gitflow-model. src. key of the main diagram image (Apple Keynote).
If you want to get in touch, I'm nvie on Twitter.
Vincent Driessen is an independent Python software engineer and consultant from the Netherlands. You may hire him.

FileCloud Blog.
Version control systems play a vital role in the success of a software development team. This blog aims to provide a simple branching and merging strategy to manage the code in a fast paced team development environment.
When do you need branching?
You may need to adopt branching in many different scenarios. Let us assume that on a day to day basis you use agile methodologies such as extreme programming or scrum and you have finally released a reasonably complex project with Version 1.0.0.0. Couple of days after the release, you get a request for a new feature that must go as Version 1.1.0.0. You envision it will take couple of weeks to get that feature coded, tested and released. Meanwhile, simple modifications and patches are requested on a day to day basis in the Version 1.0.0.0.
Essentially, with the changing business needs you are required to do a deployment every other day or so i. e. your deployment cycle is 2 days or less.
With a team of 10 developers it will be a nightmare in the absence of a proper branching strategy.
Trunk, branch, and tag are the 3 main divisions in subversion repository.
The code in trunk is always maintained as close to release state as possible. Any developer making changes to the trunk must be absolutely certain that his or her part can be coded, tested and is ready to deploy within 2 days (can vary depending on your length of deployment cycle). If it takes more than 2 days, they are not allowed to directly change the code in the trunk. They have to create a branch.
Each developer must create his or her own branch if their code will take more time to program than your normal deployment cycle. It is the responsibility of the developer to regularly (timeframe depends on your development environment) merge changes from trunk to his branch.
Create a feature branch if 2 or more developers are going to work on a new feature that will take considerable time to complete. It is the responsibility of the team lead to merge changes from trunk to this feature branch on a regular basis.
It is always beneficial to merge changes from trunk frequently. Because, after a couple of days conflict between trunk version and branch version can get out of hand and merging will practically be impossible.
When the developer branch or feature branch is ready for release, merge changes back from the branch to trunk.
Finally, remember that there is no ideal branching and merging strategy. It pretty much depends on your unique development environment. If you have any other strategy, I would like to hear about that.

No comments:

Post a Comment