A maior diferença é como os nomes das filiais são registrados no histórico. Com ramificações nomeadas, o nome da ramificação é incorporado em cada conjunto de alterações e, portanto, se torna uma parte imutável do histórico. Com os clones, não haverá registro permanente de onde veio um conjunto de alterações específico.
Isso significa que os clones são ótimos para experimentos rápidos nos quais você não deseja registrar um nome de ramificação, e ramificações nomeadas são boas para ramificações de longo prazo ("1.x", "2.x" e similares).
Observe também que um único repositório pode acomodar facilmente várias ramificações leves no Mercurial. Tais ramificações no repositório podem ser marcadas para que você possa encontrá-las facilmente novamente. Digamos que você clonou o repositório da empresa quando este se parece com:
[a] --- [b]
Você corta e faz [x]
e [y]
:
[a] --- [b] --- [x] --- [y]
Enquanto alguém coloca [c]
e [d]
no repositório, então, quando você puxa, obtém um gráfico de histórico como este:
[x] --- [y]
/
[a] --- [b] --- [c] --- [d]
Aqui existem duas cabeças em um único repositório. Sua cópia de trabalho sempre refletirá um único conjunto de alterações, o chamado conjunto de alterações pai da cópia de trabalho. Verifique isso com:
% hg parents
Digamos que ele reporte [y]
. Você pode ver as cabeças com
% hg heads
e isso irá relatar [y]
e [d]
. Se você deseja atualizar seu repositório para um checkout limpo de [d]
, basta fazer (substitua [d]
pelo número da revisão [d]
):
% hg update --clean [d]
Você verá esse hg parents
relatório [d]
. Isso significa que seu próximo commit terá [d]
como pai. Assim, você pode corrigir um erro que você notou na ramificação principal e criar o conjunto de alterações [e]
:
[x] --- [y]
/
[a] --- [b] --- [c] --- [d] --- [e]
Para enviar [e]
apenas o changeset , você precisa fazer
% hg push -r [e]
onde [e]
está o hash do conjunto de alterações. Por padrão hg push
simplesmente comparar os repositórios e ver que [x]
, [y]
e [e]
estão faltando, mas você não pode querer compartilhar [x]
e [y]
ainda.
Se o bugfix também afetar você, você deseja mesclá-lo com o seu ramo de recurso:
% hg update [y]
% hg merge
Isso deixará o gráfico do repositório assim:
[x] --- [y] ----------- [z]
/ /
[a] --- [b] --- [c] --- [d] --- [e]
onde [z]
está a mesclagem entre [y]
e [e]
. Você também pode ter optado por jogar o galho fora:
% hg strip [x]
Meu ponto principal desta história é o seguinte: um único clone pode representar facilmente várias trilhas de desenvolvimento. Isso sempre foi verdadeiro para "plain hg" sem usar nenhuma extensão. A extensão de favoritos é uma grande ajuda, no entanto. Isso permitirá que você atribua nomes (favoritos) aos conjuntos de alterações. No caso acima, você desejará um marcador em sua cabeça de desenvolvimento e um na cabeça de upstream. Os marcadores podem ser pressionados e puxados com o Mercurial 1.6 e se tornaram um recurso interno do Mercurial 1.8.
Se você tivesse optado por criar dois clones, seu clone de desenvolvimento seria assim depois de criar [x]
e [y]
:
[a] --- [b] --- [x] --- [y]
E seu clone upstream conterá:
[a] --- [b] --- [c] --- [d]
Agora você percebe o bug e o corrige. Aqui você não precisa, hg update
pois o clone upstream está pronto para uso. Você confirma e cria [e]
:
[a] --- [b] --- [c] --- [d] --- [e]
Para incluir a correção de bug no seu clone de desenvolvimento, você a puxa para lá:
[a] --- [b] --- [x] --- [y]
\
[c] --- [d] --- [e]
e mesclar:
[a] --- [b] --- [x] --- [y] --- [z]
\ /
[c] --- [d] --- [e]
O gráfico pode parecer diferente, mas tem a mesma estrutura e o resultado final é o mesmo. Usando os clones, você teve que fazer um pouco menos de contabilidade mental.
As ramificações nomeadas não entraram em cena aqui porque são bastante opcionais. O Mercurial em si foi desenvolvido usando dois clones por anos antes de passarmos a usar ramificações nomeadas. Mantemos uma ramificação chamada 'stable' além da ramificação 'default' e fazemos nossos lançamentos com base na ramificação 'stable'. Veja a página de ramificação padrão no wiki para obter uma descrição do fluxo de trabalho recomendado.
Eu acho que você quer toda a história em um repo. Desovar um repositório de curto prazo é para experimentos de curto prazo, não para grandes eventos como lançamentos.
Uma das decepções do Mercurial é que parece não haver uma maneira fácil de criar um galho de vida curta, brincar com ele, abandoná-lo e coletar o lixo. Ramos são para sempre. Simpatizo por nunca querer abandonar a história, mas os galhos descartáveis e super baratos são um
git
recurso que eu realmente gostaria de verhg
.fonte
hg strip
é o que eu quero. Por que a documentação online afirma que ramificações não podem ser excluídas?hg ci --close-branch
.Você deveria fazer as duas coisas .
Comece com a resposta aceita do @Norman: use um repositório com uma ramificação nomeada por release.
Em seguida, tenha um clone por ramificação de liberação para construção e teste.
Uma observação importante é que, mesmo se você usar vários repositórios, evite usá-lo
transplant
para mover conjuntos de alterações entre eles, porque 1) altera o hash e 2) pode introduzir bugs que são muito difíceis de detectar quando há alterações conflitantes entre o conjunto de alterações que você transplante e ramo alvo. Em vez disso, você deseja fazer a mesclagem usual (e sem pré-emergir: sempre inspecione visualmente a mesclagem), o que resultará no que o mg disse no final de sua resposta:Mais detalhadamente, se você usar vários repositórios, o repositório "trunk" (ou padrão, principal, desenvolvimento, qualquer que seja) contém TODOS os conjuntos de alterações em TODOS os repositórios. Cada repositório de release / ramificação é simplesmente uma ramificação no tronco, todas mescladas de uma maneira ou de outra para o tronco, até que você queira deixar uma versão antiga para trás. Portanto, a única diferença real entre esse repositório principal e o repositório único no esquema de ramificação nomeada é simplesmente se as ramificações são nomeadas ou não.
Isso deve tornar óbvio o motivo pelo qual eu disse "comece com um repo". Esse repositório único é o único lugar em que você precisará procurar por qualquer conjunto de alterações em qualquer versão . Você pode marcar ainda mais conjuntos de alterações nas ramificações da versão para controle de versão. É conceitualmente claro e simples, e simplifica a administração do sistema, pois é a única coisa que absolutamente precisa estar disponível e recuperável o tempo todo.
Mas ainda é necessário manter um clone por ramificação / versão que você precisa criar e testar. É trivial como você pode
hg clone <main repo>#<branch> <branch repo>
e,hg pull
no repositório de ramificação, apenas puxa novos conjuntos de alterações nesse ramo (além de conjuntos de alterações ancestrais em ramos anteriores que foram mesclados).Essa configuração se encaixa melhor no modelo de commit de kernel do linux de extrator único (não é bom agir como Lord Linus. Em nossa empresa, chamamos de integrador de funções ), pois o repositório principal é a única coisa que os desenvolvedores precisam clonar e extrator precisa puxar para dentro. A manutenção dos repositórios de filial é puramente para gerenciamento de liberação e pode ser completamente automatizada. Os desenvolvedores nunca precisam extrair / enviar para os repositórios de filial.
Aqui está o exemplo de @ mg reformulado para esta configuração. Ponto de partida:
Faça uma ramificação nomeada para uma versão de lançamento, diga "1.0", quando chegar à versão alfa. Cometa correções de erros:
(1.0)
não é um conjunto de alterações real, pois o ramo nomeado não existe até você confirmar. (Você pode fazer uma confirmação trivial, como adicionar uma tag, para garantir que as ramificações nomeadas sejam criadas corretamente.)A mesclagem
[m1]
é a chave para essa configuração. Diferente de um repositório de desenvolvedores onde pode haver um número ilimitado de cabeças, você NÃO deseja ter várias cabeças no seu repositório principal (exceto o ramo antigo de liberação morta, como mencionado anteriormente). Portanto, sempre que houver novos conjuntos de alterações nas ramificações de liberação, você deverá mesclá-las novamente à ramificação padrão (ou uma ramificação de liberação posterior) imediatamente. Isso garante que qualquer correção de bug em uma versão também seja incluída em todas as versões posteriores.Enquanto isso, o desenvolvimento na ramificação padrão continua na próxima versão:
E, como sempre, você precisa mesclar as duas cabeças na ramificação padrão:
E este é o clone da ramificação 1.0:
Agora é um exercício para adicionar o próximo ramo de lançamento. Se for 2.0, ele definitivamente se desviará do padrão. Se for 1.1, você pode optar por ramificar 1.0 ou padrão. Independentemente disso, qualquer novo conjunto de alterações na 1.0 deve ser mesclado primeiro à próxima ramificação, depois para o padrão. Isso pode ser feito automaticamente se não houver conflito, resultando apenas em uma mesclagem vazia.
Espero que o exemplo esclareça meus pontos anteriores. Em resumo, as vantagens dessa abordagem são:
UPDATE O próprio hg faz isso : o repositório principal principal contém as ramificações padrão e estável e o repositório estável é o clone da ramificação estável. Porém, ele não usa ramificação com versão, pois as tags de versão ao longo da ramificação estável são boas o suficiente para fins de gerenciamento de versão.
fonte
A principal diferença, até onde eu sei, é algo que você já declarou: o branch ramificado está em um único repositório. Ramos nomeados têm tudo à mão em um só lugar. Os repositórios separados são menores e fáceis de se mover. A razão pela qual existem duas escolas de pensamento sobre isso é que não há um vencedor claro. Qualquer argumento do lado que faça mais sentido para você provavelmente é o que você deve seguir, porque é provável que o ambiente deles seja mais semelhante ao seu.
fonte
Eu acho que é claramente uma decisão pragmática, dependendo da situação atual, por exemplo, o tamanho de um recurso / reprojeto. Eu acho que os garfos são realmente bons para os contribuidores com funções ainda não comprometidas em ingressar na equipe de desenvolvedores, provando sua aptidão com despesas técnicas negligenciáveis.
fonte
Eu realmente desaconselho o uso de ramos nomeados para versões. É para isso que servem as tags. Ramos nomeados são destinados a diversões duradouras, como um
stable
ramo.Então, por que não usar apenas tags? Um exemplo básico:
Isso criará uma nova cabeça sem nome no
default
ramo, também conhecida como. um ramo anônimo, que é perfeitamente bom em hg. Você pode, a qualquer momento, mesclar a correção do bug novamente na faixa principal de desenvolvimento. Não há necessidade de ramificações nomeadas.fonte