Usando a fusão da subárvore Git, além de se fundir em todos os ramos de todas as subárvores mescladas

StackOverflow https://stackoverflow.com/questions/2137950

  •  22-09-2019
  •  | 
  •  

Pergunta

Eu gostaria de usar um rastreador popular de edição de código aberto (Redmine) que oferece integração do Git. Infelizmente, cada projeto no rastreador só pode ser associado a um repo Git. Criar vários projetos no rastreador não é minha configuração ideal.

Com isso em mente, tentei usar a mesclagem de subárvore git (explicada aqui, e aqui). Eu criei um repo "guarda -chuva" que se fundiu em cada um dos inúmeros outros repositórios com os quais estou trabalhando.

Infelizmente, os exemplos dados apenas puxam o ramo principal de cada subárvore. Como tenho o desenvolvimento em vários ramos de cada subárvore, preciso aprender a ter esse repositório de guarda -chuva refletindo cada ramo de cada subárvore.

Isso é possível?

Crédito extra: E se 2 subáridas tiverem uma filial com o mesmo nome?

Foi útil?

Solução

Para aqueles de nós que não estão familiarizados com o Redmine, estenda sua descrição para incluir respostas às seguintes perguntas: Que tipo de acesso ao repositório o rastreador precisa? Ele precisará fazer seus próprios compromissos? Ou ele só precisa de certos tipos de acesso de leitura (talvez para validar hashes e digitalização de logs para palavras -chave)?

Se o seu rastreador precisar apenas de acesso de leitura, você pode não precisar de nenhuma subárvore. É perfeitamente aceitável ter várias confirmações iniciais (permitindo múltiplas histórias independentes) em um único repositório. O próprio projeto Git faz isso para alguns 'extras' (cara, html, façam) que compartilham não (comprometem) histórico, mas são publicados ao lado do principal conjunto de ramificações para o código -fonte (manter, mestre, próximo, pu). Para o seu propósito, pode ser suficiente configurar um controle remoto para cada sub-repositório e buscar suas dicas de ramificação no seu repositório agregado. Talvez as 'ramificações de rastreamento remotas' automáticas sejam suficientes, ou talvez você precise dar uma etapa extra para criar (e atualizar) ramificações locais com base nas filiais de rastreamento remoto.

O esquema de fusão da subárvore que você descreve provavelmente não é significativo na situação geral em que os ramos nos repositórios de origem não estão relacionados ou apenas semi-relacionados. Mas, se todos os repositórios de origem compartilharem um conjunto de ramificações em que cada ramo tiver um determinado objetivo que seja o mesmo em todos os repositórios, você provavelmente poderá mesclá-los de maneira significativa em uma espécie de superpositório.

Mas a pergunta interessante não é "E se dois repositórios tiverem ramos com o mesmo nome?", Mas "como você lida com o caso em que um repositório está faltando uma filial do conjunto compartilhado" global "?".

Se todos os sub-repositórios tiverem o mesmo conjunto de galhos, você apenas faz o que fez com mestre, mas uma vez para cada ramo. O problema ocorre quando um ramo específico está ausente de um repositório. Você poderia substituir seu mestre, mas essa nem sempre é a resposta certa. Depende de por que você está agregando os repositórios juntos em primeiro lugar e o que você espera 'ver' naquela subárvore dessa filial no super-repository.

Se os sub-repositórios forem não intimamente relacionado, então eu realmente tenho minhas dúvidas sobre a razoabilidade dessa abordagem da subárvore. Essa abordagem para repositórios não relacionados parece que seria 'ir contra os grãos'. Provavelmente ainda é possível, mas duvido que haja alguma ferramenta para ajudar, e você precisará gastar algum tempo planejando os casos de esquina.

Se você acabar com as mesclagem da subárvore, poderá olhar para o terceiro git subtree comando. Pode ajudar a manter seus inúmeros repositórios sincronizados.


Coleta de galhos, sem se fundir

Se Redmine especificar --mirror Clone, a implicação é que ele espera ramificações locais e pode não ser capaz de ler diretamente os 'Braches de rastreamento remoto', portanto, você provavelmente precisará criar e atualizar algumas filiais locais.

Filiais locais atualizadas a partir de 'ramificações de rastreamento remoto'
  • Configuração inicial

    mkdir $COLLECTION_REPO && cd $COLLECTION_REPO &&
    git init
    git remote add alpha <url/path-to-alpha-repo>
    git remote add bravo <url/path-to-bravo-repo>
    git remote add charlie <url/path-to-charlie-repo>
    for r in $(git remote); do
        git config --add remote.$r.fetch \
          "$(git config remote.$r.fetch | sed -e 's.heads.tags.;s.remotes.tags/all.')"
        git config remote.$r.tagopt --no-tags
    done
    
  • Atualização periódica

    git remote update
    git for-each-ref --shell --format \
      'git branch --force --track -l all/%(refname:short) %(refname:short)' refs/remotes \
      | sh
    
Filiais locais que recebem diretamente dicas de galhos buscados
  • Configuração inicial

    mkdir $COLLECTION_REPO && cd $COLLECTION_REPO &&
    git init
    git remote add alpha <url/path-to-alpha-repo>
    git remote add bravo <url/path-to-bravo-repo>
    git remote add charlie <url/path-to-charlie-repo>
    for r in $(git remote); do
        git config remote.$r.fetch \
          "$(git config remote.$r.fetch | sed -e 's.remotes.heads/all.')"
        git config --add remote.$r.fetch \
          "$(git config remote.$r.fetch | sed -e 's.heads.tags.g')"
        git config remote.$r.tagopt --no-tags
    done
    
  • Atualização periódica

    git remote update
    

Ambos os métodos acabam coletando galhos sob refs/heads/all/<remote-name>/<branch-name-on-remote>, mas o primeiro também tem um conjunto duplicado de refs sob refs/remotes/<remote-name>/<branch-name-on-remote>. O primeiro usa um reflexo normal e usa git branch Para duplicar os 'ramificações de rastreamento remoto' (refs/remotes/…) em ramos locais normais (refs/heads/all/…). O segundo usa um refSpec personalizado para armazenar os árbitros buscados diretamente na hierarquia de destinatários ref.

Devido à maneira como as atualizações são buscadas cegamente nesse repositório combinado, ninguém deve tentar usá -lo diretamente: nenhum compromisso feito diretamente em seus ramos, nenhum empurrão de fora. Se alguém fizesse compromissos localmente ou para empurrar uma das filiais que essas confirmações seriam eliminadas quando a próxima atualização for concluída.

Se o Redmine puder lidar com um repositório nu, eu recomendaria usar um. Usar git init --bare e um nome de repo que termina com .git. Também git config core.logAllRefUpdates true Pode ser uma boa idéia (uma vez que isso padrão é falso em um repositório nu).

além da all/ prefixo nos namespaces, outra diferença entre essa abordagem e um completo --mirror Clone é que os refs lá fora refs/heads e refs/tags não será coletado. A maioria dos outros refs comuns é considerada "local" para um repositório (e é por isso que eles não são copiados por um clone normal). Alguns dos outros árbitros são 'ramificações de rastreamento remoto' (refs/remotes), alguns registros 'bisect' manutenção (refs/bisect), git filter-branch Backups de 'original' de referência (refs/original), etc. Provavelmente nenhuma dessas outras coisas é importante para o Redmine. Se estiverem, eles também podem ser incluídos com RefSpecs adicionais.

Criando compromissos iniciais extras

Para providenciar um ramo com um novo compromisso inicial, consulte Página Gittips debaixo Como criar um novo ramo que não tem ancestral. Duas das receitas envolvem outro repositório do qual você empurra ou busca uma filial depois de passar pela etapa usual de init/add/commit (exatamente o que as receitas acima fazem de uma maneira automatizada).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top