Mesclar correções de bugs do tronco em galhos antigos

9

Agora estamos no processo de mudar de svn para git (depois de um ano em convencer as pessoas, sim!) Na minha empresa.

Até agora, isso é tudo para melhor, mas há uma coisinha que atualmente temos em nosso fluxo de trabalho que também não consigo encontrar um bom equivalente.

Atualmente, todos os nossos desenvolvedores trabalham em master. Uma vez a cada trimestre, ramificamos o master no ramo Xx, que mais tarde se tornará nosso último lançamento. Isso significa que nosso repositório svn se parece com isso:

  • tronco
  • galhos
    • 3.8
    • 4.1
    • 4.2
    • ...

Nós realmente não usamos tags.

De vez em quando, há uma correção de bug urgente que é descoberta.

A maneira atual de fazê-lo é:

  • Corrigir no mestre
  • O SVN mescla o intervalo relevante de confirmações de volta aos ramos relevantes (talvez nosso último lançamento, talvez mais).

Como estamos no setor espacial, nossas filiais têm vida longa e o processo de atualização do cliente é bastante longo, e é por isso que trabalhamos dessa maneira até agora.

Agora, como seria um bom equivalente no git?

Até agora, tentei corrigir o bug em um ramo gerado pelo mestre e, em seguida, mesclar esse ramo novamente no mestre e no 4.3 (por exemplo). O problema é que o ramo de hotfix contém o histórico mestre e todas as confirmações entre mestre e 4.3 também são mescladas, o que não queremos.

Coisas que eu conseguia pensar até agora:

  • Analisei o muito bem-sucedido método Git Workflow , e sua solução é corrigir o bug no ramo de lançamento e mesclá-lo novamente, e não o contrário. Isso pode funcionar no nosso caso, mas seria bastante complicado, porque exigiria que já soubéssemos o ramo mais antigo em que queremos corrigir o erro antes de realmente corrigi-lo.
  • Outra solução é consertar no master e depois escolher os commits (como fazemos hoje para a fusão svn). A coisa chata aqui é que, nesse caso, perdemos a história do que foi fundido no passado, já que as escolhas da cereja parecem novos comprometimentos e perdemos o relacionamento.

Então, qual é a maneira "boa" de fazer isso? Devemos consertar confirmações na história ou escolher manualmente e acompanhar manualmente o que foi mesclado, ou mesmo algo mais?

Se tiver pouca experiência em produção com o git, tenho certeza que posso ter perdido alguma coisa.

jlengrand
fonte

Respostas:

9

O Git Flow supõe que você tenha apenas uma única versão suportada, com a masterramificação sempre apontando para a versão mais recente. Como você oferece suporte a várias versões simultaneamente, não é possível copiar esse fluxo de trabalho 1: 1. O Git Flow da Nvie é um exemplo muito bom de uma estratégia de ramificação, mas você deve adaptá-la às suas necessidades. Mais importante, você terá várias ramificações de versão ativas.

Ao identificar um bug, você precisará fazer alguns testes para determinar todas as versões afetadas. Não é suficiente escrever a correção primeiro e depois mesclá-la novamente nos ramos da versão como um hotfix. Geralmente, você acaba com um intervalo contínuo de versões afetadas. Versões muito antigas podem não conter o bug, versões mais recentes podem ter corrigido o bug acidentalmente. Você precisará verificar o bug em cada versão para poder verificar se ele realmente desapareceu após a correção. Se você pode expressar o bug como uma caixa de teste automatizada, é bastante simples encontrar a confirmação problemática via git bisectou executar o teste para cada versão:

for release in 3.8 4.1 4.2
do
  git checkout $release
  if ./testcase >release-$release.log
  then echo "$release ok"
  else echo "$release AFFECTED"
  fi
done

Agora, você costumava escrever a correção em trunk/ master. Isso é problemático porque a parte do buggy pode ter sido alterada entre as versões; portanto, um patch geralmente não se aplica a uma versão mais antiga. Em particular, o código masterpode depender de quaisquer recursos disponíveis no mestre, que podem não estar presentes nas versões mais antigas. Portanto, faz muito sentido que um commit do Git faça referência a toda a sua história, não apenas ao conjunto de mudanças. Ao mesclar novamente, ele puxará toda a história da qual depende.

O uso cherry-pickou rebaseignora esse histórico e registra uma nova confirmação com o mesmo conjunto de alterações, mas com um histórico diferente. Conforme indicado, isso não funcionará se a sua base de código tiver divergido.

A solução "correta" é gravar a correção como um hotfix na versão afetada mais antiga. Em seguida, você mescla a versão mais antiga com a segunda versão mais antiga. Normalmente, uma versão mais recente conteria todos os commit de uma versão mais antiga, portanto, tudo bem. Se as coisas mudaram, agora você tem a chance de resolver manualmente o conflito de mesclagem. Em seguida, você continua mesclando cada release no próximo lançamento mais novo até concluir. Isso mantém um histórico adequado e evita muito trabalho desnecessário, exigindo apenas esforços que precisam ser gastos de qualquer maneira. Em particular, essa mesclagem incremental aproxima você do estado atual de desenvolvimento em pequenas etapas.

Como um diagrama:

| o normal commit |
| x hotfix        |
| ⇘ merging       |

3.8 --o-----------------x
       \                 ⇘
4.1     o--o--o-----------x'
               \           ⇘
4.2             o--o--o-----x''
                       \     ⇘
develop                 o--o--x'''--o--o
amon
fonte
2
Para completar, digamos que o teste estava um pouco errado e a versão 3.7 tem o mesmo bug (digamos, só acontece em um caso de ponta na 3.7, mas acontece em casos mais facilmente testados em 3.8+), mas só foi descoberta após o correção foi mesclada assim. Você apenas escolheria nesse ponto?
Izkata
2
@ Izkata: sim, nesse momento não é mais possível fingir que existe algum tipo de histórico sensato; portanto, escolher a cereja é uma boa maneira de aplicar as alterações em uma versão anterior. No entanto, isso implica que as ramificações da versão divergiram e as versões mais recentes não contêm mais todos os commits de versões mais antigas. Portanto, devemos fazer a cadeia de mesclagem novamente a partir do lançamento que alteramos para o ramo de desenvolvimento. No entanto, durante a primeira mesclagem, podemos descartar as alterações selecionadas desde que já aplicamos a correção na versão mais recente.
amon
Obrigado por responder @amon. Sua resposta é muito completa e está indo na direção que eu já estava olhando, por isso é bom ter validação. Assumiremos nossos próprios requisitos da indústria e adaptaremos a abordagem de fluxo git a algo que nos encaixe melhor. Obrigado novamente!
jlengrand