Atualmente, nossa empresa está usando um modelo de ramificação simples de tronco / release / hotfixes e gostaria de receber conselhos sobre quais modelos de ramificação funcionam melhor para sua empresa ou processo de desenvolvimento.
Fluxos de trabalho / modelos de ramificação
Abaixo estão as três principais descrições que eu já vi, mas elas se contradizem parcialmente ou não vão longe o suficiente para resolver os problemas subseqüentes nos quais encontramos (conforme descrito abaixo). Portanto, nossa equipe, até o momento, adota soluções não tão boas. Você está fazendo algo melhor?
Mesclando vs rebasing (emaranhado x histórico seqüencial)
Deve-se
pull --rebase
esperar com a mesclagem de volta à linha principal até que sua tarefa seja concluída? Pessoalmente, eu me inclino para a mesclagem, pois isso preserva uma ilustração visual de em que base uma tarefa foi iniciada e finalizada, e eu até prefiromerge --no-ff
para esse fim. No entanto, há outras desvantagens. Muitos também não perceberam a propriedade útil da mesclagem - que não é comutativa (mesclar um ramo de tópico no mestre não significa mesclar o mestre no ramo de tópico).Estou procurando um fluxo de trabalho natural
Às vezes, erros acontecem porque nossos procedimentos não capturam uma situação específica com regras simples. Por exemplo, uma correção necessária para liberações anteriores deve, obviamente, ser baseada suficientemente a jusante para que seja possível mesclar a montante em todas as ramificações necessárias (o uso desses termos é claro o suficiente?). No entanto, acontece que uma correção entra no mestre antes que o desenvolvedor perceba que deveria ter sido colocado mais a jusante, e se isso já foi enviado (ainda pior, mesclado ou algo com base nele), a opção restante é escolher a cereja, com seus perigos associados. Que regras simples como essas você usa?Também está incluído o constrangimento de uma ramificação de tópico, excluindo necessariamente outras ramificações de tópico (supondo que elas sejam ramificadas a partir de uma linha de base comum). Os desenvolvedores não querem concluir um recurso para iniciar outro, sentindo que o código que acabaram de escrever não existe mais
Como evitar a criação de conflitos de mesclagem (devido à seleção de cereja)?
O que parece uma maneira certa de criar um conflito de mesclagem é escolher entre ramificações, elas nunca poderão ser mescladas novamente? A aplicação do mesmo commit na reversão (como fazer isso?) Em qualquer ramo possivelmente resolveria essa situação? Esse é um dos motivos pelos quais não me atrevo a pressionar por um fluxo de trabalho amplamente baseado em mesclagem.
Como se decompor em ramos tópicos?
Percebemos que seria incrível montar uma integração finalizada das ramificações de tópicos, mas muitas vezes o trabalho de nossos desenvolvedores não está claramente definido (às vezes, tão simples quanto "bisbilhotar") e se algum código já tiver entrado em um tópico "misc", não pode ser retirado de lá novamente, de acordo com a pergunta acima? Como você trabalha para definir / aprovar / formar / liberar suas ramificações de tópicos?
É claro que procedimentos adequados, como revisão de código e graduação, seriam adoráveis.
Mas simplesmente não podemos manter as coisas emaranhadas o suficiente para gerenciar isso - alguma sugestão? ramos de integração, ilustrações?
Abaixo está uma lista de perguntas relacionadas:
- Quais são algumas boas estratégias para permitir que os aplicativos implantados sejam corrigidos?
- Descrição do fluxo de trabalho para uso do Git para desenvolvimento interno
- Fluxo de trabalho Git para desenvolvimento corporativo de kernel Linux
- Como você mantém o código de desenvolvimento e o código de produção? (obrigado por este PDF!)
- gerenciamento de lançamentos git
- Git Cherry-pick vs Merge Workflow
- Como escolher várias confirmações de cereja
- Como você mescla arquivos seletivos com o git-merge?
- Como escolher uma variedade de confirmações e mesclar em outra ramificação
- ReinH Git Workflow
- fluxo de trabalho git para fazer modificações que você nunca voltará à origem
- Escolha uma mesclagem de cereja
- Fluxo de trabalho Git adequado para SO e código privado combinados?
- Mantendo o projeto com o Git
- Por que o arquivo de mesclagem Git não pode ser alterado com um pai / mestre modificado.
- Boas práticas de ramificação / reestruturação do Git
- Quando o "git pull --rebase" me leva a problemas?
- Como o DVCS é usado em equipes grandes?
Verifique também o que o Plastic SCM escreve sobre o desenvolvimento orientado a tarefas e, se o Plastic não for sua escolha, estude o modelo de ramificação do nvie e seus scripts de suporte .
Respostas:
O recurso mais preocupante que os novos desenvolvedores do DVCS precisam entender é o processo de publicação :
A partir disso, você pode respeitar algumas regras para facilitar suas perguntas:
Agora:
Modelos de fluxos de trabalho / ramificação :
cada fluxo de trabalho existe para oferecer suporte a um processo de gerenciamento de liberação e é adaptado para cada projeto.
O que posso acrescentar ao fluxo de trabalho que você menciona é: cada desenvolvedor não deve criar um ramo de recurso, apenas um ramo "dev atual", porque a verdade é: o desenvolvedor geralmente não sabe exatamente o que seu ramo produzirá: um recurso, vários (porque acabou sendo um recurso muito complexo), nenhum (porque não está pronto a tempo do lançamento), outro recurso (porque o original havia "se transformado"), ...
Somente um "integrador" deve estabelecer ramificações oficiais de recursos em um repositório "central", que pode ser buscado pelos desenvolvedores para refazer / mesclar a parte do trabalho que se encaixa nesse recurso.
Mesclagem vs rebasing (emaranhado x histórico seqüencial) :
Gosto da minha resposta que você mencionou (" Descrição do fluxo de trabalho para uso do git para desenvolvimento interno ")
Estou procurando um fluxo de trabalho natural :
para correções, ele pode ajudar a associar cada correção a um ticket de um rastreamento de bug, o que ajuda o desenvolvedor a lembrar onde (por exemplo, em qual filial, ou seja, uma filial dedicada "para correções") ele / ela deve cometer essas modificações.
Então, hooks podem ajudar a proteger um repositório central contra ataques de correções de bugs não validadas ou de ramos dos quais não se deve pressionar. (nenhuma solução específica aqui, tudo isso precisa ser adaptado ao seu ambiente)
Como evitar a criação de conflitos de mesclagem (devido à seleção de cereja)?
Como afirmou Jakub Narębski em sua resposta , a colheita de cerejas deve ser reservada para situações raras em que é necessária.
Se a sua configuração envolve muitas escolhas (ou seja, "não é raro"), algo está errado.
git revert
deve cuidar disso, mas isso não é o ideal.Desde que um ramo ainda não tenha sido enviado a todos os lugares, um desenvolvedor deve reorganizar seu histórico de confirmações (quando finalmente vê o desenvolvimento assumir uma forma mais definitiva e estável) em:
Procedimentos adequados, como revisão de código e graduação?
O repositório de ramificações de integração (em uma integração dedicada) pode ajudar o desenvolvedor a:
fonte
rebase --interactive --autosquash
que se moverá automaticamente todos os commit com o mesmo início de outra mensagem de commit. Se essas confirmações usarem um número de ticket (por exemplo), mesmo que as correções relacionadas a essa permissão não tenham sido feitas seqüencialmente no momento, o autosquash permitirá uma rápida reordenação dessas confirmações.Eu acho que posso estar errado, e que uma das coisas mais incompreendidas sobre o git é sua natureza distribuída. Isso torna muito diferente dizer subversão da maneira que você pode trabalhar, embora possa imitar o comportamento do SVN, se desejar. O problema é praticamente qualquer fluxo de trabalho, o que é ótimo, mas também enganoso.
Se eu entendo direito o desenvolvimento do kernel (vou me concentrar nisso), todo mundo tem seu próprio repositório git para desenvolver o kernel. Existe um repositório, linux-2.6.git, que o Torvalds cuida, que atua como repositório de lançamento. As pessoas clonam daqui se desejam começar a desenvolver um recurso no ramo "release".
Outros repositórios fazem algum desenvolvimento. A idéia é clonar do linux-2.6, ramificar quantas vezes você quiser até um ponto em que você tenha um recurso "novo" em funcionamento. Então, quando estiver pronto, você poderá disponibilizá-lo para alguém considerado confiável, que puxará esse ramo do seu repositório para o deles e o mesclará no mainstream. No kernel do linux, isso acontece em vários níveis (tenentes de confiança) até atingir o linux-2.6.git, momento em que se torna "o kernel".
Agora aqui é onde fica confuso. Os nomes das filiais não precisam ser consistentes entre os repositórios. Para que eu possa
git pull origin master:vanilla-code
obter uma ramificação doorigin
mestre da ramificação no meu repositório chamadavanilla-code
. Desde que eu saiba o que está acontecendo, isso realmente não importa - ele é distribuído no sentido de que todos os repositórios são pares e não apenas compartilhados em vários computadores como o SVN.Então, com tudo isso em mente:
head
. As versões podem ser tags ou ramificações e os hotfixes provavelmente são ramificações em si. Na verdade, eu provavelmente faria lançamentos como ramificações para que você possa continuar corrigindo-os.origin
que você deve, em seu repositório, provavelmente, fazer um outro ramo e mesclar o mais recentemaster
emyourbranch
para que outra pessoa pode puxar suas alterações com o mínimo de esforço possível. Raramente há uma necessidade de me refazer verdadeiramente, na minha experiência.git add .
e , em seguidagit commit
.Espero que ajude. Percebo que o VonC acabou de postar uma explicação muito parecida ... Não consigo digitar rápido o suficiente!
Edite algumas idéias adicionais sobre como usar o git em um ambiente comercial, pois isso parece relevante para o OP nos comentários:
product.git
, é acessível por vários programadores seniores / pessoas técnicas responsáveis por realmente cuidar do produto. Eles são análogos ao papel dos mantenedores no OSS.Então o que acontece? Bem, todo mundo puxa no início de cada dia a partir da fonte "upstream", isto é, o repositório de lançamento (que provavelmente também conterá o material mais recente do desenvolvimento dos dias anteriores). Todo mundo faz isso diretamente. Isso irá para um ramo em seu repositório, provavelmente chamado de "mestre" ou talvez se você me chamou de "mais recente". O programador fará algum trabalho. Esse trabalho pode ser algo sobre o qual eles não têm certeza; portanto, eles fazem uma filial, fazem o trabalho. Se não funcionar, eles podem excluir a ramificação e voltar. Se isso acontecer, eles terão que se unir ao ramo principal no qual estão trabalhando no momento. Diremos que este é um programador de interface do usuário trabalhando
latest-ui
,git checkout latest-ui
seguido porgit merge abc-ui-mywhizzynewfeature
. Ele então diz ao seu líder técnico (o líder da interface do usuário) ei, eu concluí essa tarefa, retire-me. O líder da interface do usuário simgit pull user-repo lastest-ui:lastest-ui-suchafeature-abc
. O lead da interface do usuário, então, olha para esse ramo e diz: na verdade, é muito bom, eu o mesclareiui-latest
. Ele pode então dizer a todos que estão abaixo dele para puxá-lo em seusui-latest
galhos ou em qualquer nome que eles deram a eles, para que o recurso seja explorado pelos desenvolvedores. Se a equipe estiver satisfeita, o líder da interface do usuário poderá solicitar que o líder de teste o retire e mescle as alterações. Isso se propaga a todos (a jusante da mudança) que o testam e enviam relatórios de bugs, etc. Finalmente, se o recurso passa no teste, etc., um dos principais líderes técnicos pode fundi-lo na cópia de trabalho atual do programa, momento em que todas as alterações são propagadas novamente. E assim por diante.Não é uma maneira "tradicional" de trabalhar e foi projetada para ser "orientada por pares" e não "hierárquica" como SVN / CVS. Em essência, todos têm acesso confirmado, mas apenas localmente. É o acesso ao repositório e qual repositório você designa como o repositório de liberação que permite usar a hierarquia.
fonte
Um modelo que eu usei com bons resultados é o seguinte:
Um repositório "abençoado" que todos enviam e recebem de / para, basicamente uma topologia cliente-servidor.
Como não há ramificação principal, nenhum desenvolvedor pode inserir nenhum código na "linha principal".
Todos os desenvolvimentos acontecem em tópicos. Nós colocamos nomes no namespace para detectar facilmente quem é responsável por ele: jn / newFeature ou jn / issue-1234
Há também um mapeamento quase 1 para 1 entre filiais e cartões kanban / scrum no quadro branco.
Para liberar um ramo, ele é enviado para o repo abençoado e o cartão Kanban é movido para pronto para revisão.
Então, se a ramificação for aceita pela revisão, ela é candidata a uma liberação.
Uma liberação acontece quando um conjunto de ramificações aceitas é mesclado e marcado com um número de versão.
Ao levar a nova tag para o repo abençoado, há uma nova base possível para novos recursos.
Para evitar conflitos de mesclagem, os desenvolvedores devem atualizar (mesclar) suas ramificações não lançadas na tag de lançamento mais recente.
fonte
Pessoalmente, tento manter apenas o código pronto para lançamento na ramificação principal.
Quando trabalho em um novo recurso ou correção de bug, faço isso em uma ramificação. Eu também teste unitário no ramo. Se tudo der certo, só então eu mesclar / refazer o master.
Também tento usar convenções comuns de nomenclatura de ramificações, como:
fonte