A ramificação quebra a integração contínua?

18

Acho que este artigo, um modelo de ramificação com êxito no Git , é muito conhecido entre os usuários experientes do DVCS.

Eu uso hgprincipalmente, mas eu diria que essa discussão é boa para qualquer DVCS.

Nosso fluxo de trabalho atual é que cada desenvolvedor clona o repositório principal. Escrevemos código em nosso próprio repositório local, executamos testes e, se tudo correr bem, empurra o mestre.

Portanto, queremos configurar servidores de CI como Jenkins e melhorar nosso fluxo de trabalho com o futuro sistema de provisionamento (chef, fantoche, ansible, etc.).

Parte real

Bem, o modelo apresentado acima funciona bem, mas os ramos podem quebrar o IC. A ramificação do recurso deve sincronizar com a origem (de acordo com o artigo, seria developmentramificação) para tornar o CI e a mesclagem suaves, certo?

Digamos que Alice e Bob estão trabalhando em dois recursos. Mas Alice está pronta no dia seguinte. O recurso de Bob leva uma semana. Quando Bob termina, suas alterações estão desatualizadas (talvez Alice refatorou / renomeou algumas classes).

Uma solução é a cada manhã que os desenvolvedores devem master/originprocurar para verificar se há alguma alteração. Se Alice se comprometer, Bob deve puxar e mesclar em seu espaço de trabalho para que seu ramo de recursos esteja atualizado.

  1. Essa é uma boa maneira?
  2. Essas ramificações devem existir no repositório principal (não no clone local?). O que significa que todo desenvolvedor deve conceder privilégios ao repositório principal no GitHub / Bitbucket para que eles possam criar uma nova ramificação? Ou isso é feito localmente?
  3. Por fim, o modelo apresentado pelo artigo deve interromper o IC se as ramificações não estiverem sincronizadas com o origin/master. Como queremos criar a construção todas as noites, os desenvolvedores devem puxar e mesclar antes de deixar o trabalho, e o CI também é executado em cada ramo de recurso?
CppLearner
fonte

Respostas:

12

Antes de tudo, o uso de ramificações de recursos (para isolar o trabalho realizado em um recurso) e o IC (para encontrar problemas de integração assim que eles são confirmados) estão ligeiramente em desacordo.

Na minha opinião, executar o CI em ramos de recursos é uma perda de tempo. Como as ramificações dos recursos vão e vêm com frequência, as ferramentas de IC precisam ser reconfiguradas repetidamente. E isso para uma filial que provavelmente só recebe atualizações de uma ou duas fontes que coordenam seus check-ins para evitar os problemas que um sistema de IC deve detectar.
Portanto, também não há sentido em ter o recurso ramificado no servidor de repositório principal.

Quanto às perguntas 1 e 3: É responsabilidade do desenvolvedor garantir que a construção no ramo de desenvolvimento principal não seja interrompida quando ele mesclar seu ramo de recursos. Como eles fazem isso é problema deles, mas duas maneiras possíveis são:

  • Coloque regularmente as alterações feitas no ramo principal de desenvolvimento no ramo de recursos (por exemplo, diariamente)
  • Quando o recurso estiver concluído, mescle o ramo de desenvolvimento principal no ramo de recurso e envie o resultado da mesclagem para o ramo de desenvolvimento principal.

Nos dois casos, os problemas óbvios de integração (por exemplo, classes / arquivos renomeados) são encontrados e corrigidos primeiro na ramificação do recurso. Os problemas mais sutis provavelmente só são encontrados quando a compilação noturna é executada e devem ser corrigidos lá e depois.

Bart van Ingen Schenau
fonte
Concordo que o uso de ramos de recursos está (ligeiramente) em desacordo com o conceito de IC. No entanto, é possível criar um sistema de IC que não exija reconfiguração para executar nas ramificações de recursos. (Eu já fiz isso no passado com alguns scripts python simples) e pode ser útil quando os ramos "feature" estão realmente sendo usados ​​como ramos de estabilização de versão, onde o IC é absolutamente necessário.
William Payne
1
Na verdade, acho que precisamos de duas ramificações "centrais" - uma como uma ramificação "throwaway_integration" que existe apenas como uma verificação rápida de mesclagem e teste de recursos ativamente em desenvolvimento e outra ramificação "principal" ou "estável" que contém recursos após atingirem um certo nível de estabilidade / maturidade. Os desenvolvedores extraem o código estável para trabalhar a partir do segundo ramo "stable" / "master" e mesclam e enviam alterações com freqüência para o primeiro ramo "instável" / "throwaway_integration". Os testes de CI devem ser executados nos dois ramos, é claro.
William Payne
@WilliamPayne: Acredito que um ramo tão "instável" seja chamado "desenvolver"
Bart van Ingen Schenau
5

Em resposta a 1)

Qualquer maneira que funcione é uma boa maneira. No entanto : toda a premissa da integração contínua é integrar continuamente . A idéia é capturar os erros de integração não apenas o mais cedo possível, mas dentro do ciclo de feedback do desenvolvimento - ou seja, enquanto todos os detalhes do código em teste estão na memória de curto prazo do desenvolvedor que faz as alterações. Isso significa que, em circunstâncias normais do dia-a-dia, o trabalho deve ser integrado entre as ramificações dos recursos em cada consolidação - talvez uma vez a cada 15 minutos. Reiterar: O principal objetivo da integração contínua é expor os erros de integração enquanto todos os detalhes estão na memória de curto prazo do (s) desenvolvedor (es) que estão fazendo as alterações.

2)

Principalmente, as ramificações são criadas no Mercurial pela clonagem de repositórios, portanto, você não precisa conceder a todos os desenvolvedores privilégios de confirmação para o repositório principal. Você provavelmente, no entanto, deseja oferecer aos desenvolvedores a capacidade de criar repositórios clonados no servidor de integração contínua, pois nem sempre é possível executar testes localmente. (Uma vez eu tinha um sistema de IC em que os testes de unidade demoravam 8 horas para serem executados em um cluster de 128 núcleos) - Escusado será dizer que os desenvolvedores não, não podiam executar testes localmente.

3)

Se você possui os recursos computacionais para isso, sim, os desenvolvedores devem estar sempre atualizados com a linha principal de desenvolvimento, especialmente antes de deixarem o trabalho, e você deve executar testes noturnos em todas as linhas de desenvolvimento (embora a maioria dos sistemas de CI não facilite isso).

William Payne
fonte
1
"Principalmente, as ramificações são criadas no Mercurial por clonagem de repositórios" - isso pode ter sido verdade em 2013, mas hoje em dia, os indicadores do Mercurial são funcionalmente equivalentes aos ramos do Git, exceto o nome.
Kevin
@ Kevin: Você provavelmente está certo. Uso o git (quase) exclusivamente desde fevereiro de 13 - cerca de um mês depois de escrever a resposta acima ... então não estou particularmente atualizado sobre as mudanças que aconteceram no Mercurial desde então.
William Payne
1

Aqui está como você pode fazer isso: ramificação de recursos.

  1. Para qualquer nova tarefa (correção de bug, recurso etc.), inicie uma nova ramificação (por exemplo, bugfix-ticket123-the_thingie_breaks)
  2. Enquanto você trabalha, atualize e mescle continuamente o padrão (ou domine o git) em sua ramificação de recursos . Isso ajuda você a atualizar sua filial sem precisar trabalhar na ramificação padrão
  3. Quando seu recurso estiver pronto e seus testes de unidade forem aprovados , puxe e mescle o padrão novamente para o seu ramo, feche o ramo e empurre-o sem mesclar , seu integrador notará o novo cabeçalho e que é um ramo fechado, portanto ele vai cuidar de integrá-lo. Se você não tiver um integrador, mude para o padrão e mescle a ramificação do recurso para o padrão .

O importante aqui é que você terá 0 conflitos na ramificação padrão ao mesclar sua ramificação de recursos e todos os seus testes serão aprovados .

Com esse fluxo de trabalho simples, você sempre terá uma ramificação padrão pura e estável, agora faça o mesmo para ramificações de liberação, mas integrando-a por padrão . Se você precisar integrar os hotfixes diretamente nas ramificações de liberação, ainda poderá fazer isso ignorando a ramificação padrão, mas novamente, escolhendo apenas ramificações que foram atualizadas a partir da ramificação de destino e não tenham conflitos e seus testes de unidade serão aprovados.

dukeofgaming
fonte
Você mistura e substitui coisas bastante ortogonais. ! 0 merge conflito = 0 defeituoso-teste de unidade, fusão de sucesso = código de sucesso
preguiçoso Badger
Adicionado alguns esclarecimentos, esqueci de mencionar que os testes de unidade deve passar também :)
dukeofgaming