Atualização do sub-módulo Git

242

Não sei ao certo o que significa o seguinte (na documentação de atualização do submódulo Git ):

... vai fazer a cabeça submódulos ser destacado, a menos que --rebaseou --mergeé especificado ...

Como --rebase/ --mergemuda as coisas?

Meu principal caso de uso é ter vários repositórios centrais, que incorporarei por meio de submódulos em outros repositórios. Eu gostaria de poder melhorar esses repositórios centrais, diretamente em seu local original ou de dentro de seus repositórios de incorporação (aqueles que os usam por meio do submódulo).

  • A partir desses submódulos, posso criar ramificações / modificações e usar push / pull como faria em repositórios regulares ou há coisas a serem cautelosas?
  • Como eu avançaria o commit do submódulo referenciado de say (tagged) 1.0 para 1.1 (mesmo que o chefe do repositório original já esteja em 2.0), ou escolher qual commit do branch é usado?
azul profundo
fonte
No tópico "cabeça desanexada", consulte também stackoverflow.com/questions/964876/head-and-orighead-in-git e stackoverflow.com/questions/237408/… para obter um exemplo prático (não relacionado ao sub-módulo, mas ainda )
VonC 30/12/2009
"você não pode modificar o conteúdo do submódulo de dentro do projeto principal": sim, é verdade. E eu editei a minha resposta para lançar alguma luz sobre esta aparente contradição (submodule não modificável, que você ainda pode modificar a partir da principal repo projeto!)
VonC

Respostas:

304

Esta página do GitPro resume bem as consequências de uma atualização do sub-módulo git

Quando você executa git submodule update, ele faz check-out da versão específica do projeto, mas não dentro de uma ramificação. Isso é chamado de ter uma cabeça desanexada - significa que o arquivo HEAD aponta diretamente para uma confirmação, não para uma referência simbólica.
O problema é que geralmente você não deseja trabalhar em um ambiente desanexado, porque é fácil perder alterações .
Se você fizer uma atualização inicial do sub-módulo, confirme nesse diretório de sub-módulo sem criar uma ramificação para trabalhar e execute a atualização do sub-módulo git novamente a partir do superprojeto sem confirmar, o Git substituirá suas alterações sem avisar. Tecnicamente, você não perderá o trabalho, mas não terá um ramo apontando para ele, por isso será um pouco difícil de recuperar.


Nota de março de 2013:

Como mencionado em " git submódulo mais recente ", um submódulo agora (git1.8.2) pode rastrear uma ramificação.

# add submodule to track master branch
git submodule add -b master [URL to Git repo];

# update your submodule
git submodule update --remote 
# or (with rebase)
git submodule update --rebase --remote

Veja " git submodule update --remotevsgit pull ".

A resposta do MindTooth ilustra uma atualização manual (sem configuração local):

git submodule -q foreach git pull -q origin master

Nos dois casos, isso alterará as referências dos submódulos (o gitlink , uma entrada especial no índice do repositório pai ), e você precisará adicionar, confirmar e enviar as referências do repositório principal.
Da próxima vez que você clonar esse repositório pai, ele preencherá os submódulos para refletir essas novas referências SHA1.

O restante desta resposta detalha o recurso clássico do submódulo (referência a um commit fixo , que é o ponto principal da noção de submódulo).


Para evitar esse problema, crie uma ramificação ao trabalhar em um diretório de submodule com git checkout -b work ou algo equivalente. Quando você faz a atualização do submódulo pela segunda vez, ele ainda reverte seu trabalho, mas pelo menos você tem um ponteiro para retornar.

Alternar ramificações com submódulos também pode ser complicado. Se você criar uma nova ramificação, adicionar um submódulo lá e voltar para uma ramificação sem esse submódulo, você ainda terá o diretório do submódulo como um diretório não rastreado:


Então, para responder suas perguntas:

posso criar ramificações / modificações e usar push / pull como faria em repositórios regulares ou há coisas a serem cautelosas?

Você pode criar uma ramificação e enviar modificações.

AVISO (do Tutorial do Git Submodule ): Sempre publique (envie) a alteração do submódulo antes de publicar (envie) a alteração no superprojeto que o referencia. Se você esquecer de publicar a alteração do submódulo, outros não poderão clonar o repositório.

como eu avançaria o commit do submódulo referenciado de say (tagged) 1.0 para 1.1 (mesmo que o chefe do repo original já esteja em 2.0)

A página " Entendendo os submódulos " pode ajudar

Os submódulos Git são implementados usando duas partes móveis:

  • o .gitmodulesarquivo e
  • um tipo especial de objeto de árvore.

Juntos, eles triangulam uma revisão específica de um repositório específico, que é registrada em um local específico no seu projeto.


Na página do submódulo git

você não pode modificar o conteúdo do submódulo de dentro do projeto principal

100% correto: você não pode modificar um submódulo, consulte apenas um de seus commit.

É por isso que, quando você modifica um submódulo de dentro do projeto principal, você:

  • precisa confirmar e enviar dentro do submódulo (para o módulo upstream) e
  • em seguida, suba em seu projeto principal e confirme novamente (para que o projeto principal se refira ao novo submódulo que você acabou de criar e enviar)

Um submódulo permite que você desenvolva uma abordagem baseada em componentes , onde o projeto principal se refere apenas a confirmações específicas de outros componentes (aqui "outros repositórios Git declarados como submódulos").

Um submódulo é um marcador (confirmação) para outro repositório Git que não é vinculado pelo ciclo principal de desenvolvimento do projeto: ele (o "outro" repositório Git) pode evoluir independentemente.
Cabe ao projeto principal escolher desse outro repositório qualquer que seja a confirmação necessária.

No entanto, se você quiser, por conveniência , modificar um desses submódulos diretamente do seu projeto principal, o Git permite que você faça isso, desde que você primeiro publique essas modificações do submódulo no repositório original do Git e, em seguida, comprometa seu projeto principal, referindo-se a uma nova versão do referido submódulo.

Mas a idéia principal permanece: referenciar componentes específicos que:

  • tem seu próprio ciclo de vida
  • tem seu próprio conjunto de tags
  • tem seu próprio desenvolvimento

A lista de confirmações específicas às quais você está se referindo no seu projeto principal define sua configuração (é disso que se trata o Gerenciamento de Configurações , englobando apenas o Sistema de Controle de Versão )

Se um componente pudesse realmente ser desenvolvido ao mesmo tempo que o projeto principal (porque qualquer modificação no projeto principal envolveria a modificação do subdiretório e vice-versa), seria um "submódulo" não mais, mas um mesclagem de subárvore (também apresentada na pergunta Transferindo a base de código herdada do cvs para o repositório distribuído ), vinculando o histórico dos dois repositórios Git.

Isso ajuda a entender a verdadeira natureza dos submódulos do Git?

VonC
fonte
77
Uau. Essa longa explicação para algo que é principalmente simples deve ser suficiente para assustar qualquer iniciante a se ater ao svn: externals. ;-)
conny
2
@conny: mas, como detalho em " Por que os sub-módulos git são incompatíveis com o svn externals? ", os sub-módulos são fundamentalmente diferentes e não são compatíveis com svn:externals.
VonC 15/01/11
1
Desculpe, para responder minha própria pergunta, reuno cd'ing no submódulo e git checkout a sha, ou git pull / fetch irá funcionar bem. Em seguida, confirme a atualização no repositório local.
Henrik
2
@ hced: Você também pode acessar todos os submódulos de uma só vez usandogit submodule foreach
Dav Clark
1
.. ainda não entendi. existe uma explicação mais fácil na web em algum lugar?
Eugene
135

Para atualizar cada submódulo, você pode chamar o seguinte comando (na raiz do repositório):

git submodule -q foreach git pull -q origin master

Você pode remover a opção -q para seguir todo o processo.

MindTooth
fonte
15
Se você apenas executar a git submodule update --init --recursivepartir da raiz, ele obterá todos eles recursivamente e os inicializará se ainda não o forem.
Sam Soffes
10
@SamSoffes Isso serve a um propósito completamente diferente. Atualizando submódulos irá verificar os submódulos ao cometer eles estão atualmente apontando para (não necessariamente o mais recente commit). A solução na resposta acima atualiza o commit de cada submódulo para o HEAD mais recente da origem / mestre.
indragie
7
Meu novo método:git submodule update --rebase --remote
MindTooth 19/02
19

Para abordar a opção --rebasevs.--merge

Digamos que você tenha o super repositório A e o submódulo B e queira fazer algum trabalho no submódulo B. Você fez sua lição de casa e sabia disso depois de ligar

git submodule update

você está em um estado sem cabeça, portanto é difícil voltar a qualquer confirmação que fizer neste momento. Então, você começou a trabalhar em uma nova ramificação no submódulo B

cd B
git checkout -b bestIdeaForBEver
<do work>

Enquanto isso, alguém no projeto A decidiu que a versão mais recente e melhor de B é realmente o que A merece. Por hábito, você mescla as alterações mais recentes e atualiza seus submódulos.

<in A>
git merge develop
git submodule update

Oh não! Você voltou ao estado sem cabeça novamente, provavelmente porque B agora está apontando para o SHA associado à nova dica de B ou a algum outro commit. Se você tivesse:

git merge develop
git submodule update --rebase

Fast-forwarded bestIdeaForBEver to b798edfdsf1191f8b140ea325685c4da19a9d437.
Submodule path 'B': rebased into 'b798ecsdf71191f8b140ea325685c4da19a9d437'

Agora que a melhor idéia de sempre para B foi reformulada no novo commit, e mais importante, você ainda está no ramo de desenvolvimento de B, e não em um estado decapitado!

(A --mergemesclagem será alterada de beforeUpdateSHA para afterUpdateSHA em sua ramificação de trabalho, em vez de reformular suas alterações para afterUpdateSHA.)

robinspb
fonte
7

O Git 1.8.2 apresenta uma nova opção,, --remoteque permitirá exatamente esse comportamento. Corrida

git submodule update --rebase --remote

buscará as alterações mais recentes do upstream em cada submódulo, as reorganizará e verificará a revisão mais recente do submódulo. Como a documentação coloca:

--controlo remoto

Esta opção é válida apenas para o comando update. Em vez de usar o SHA-1 registrado do superprojeto para atualizar o submódulo, use o status da ramificação de rastreamento remoto do submódulo.

Isso é equivalente à execução git pullem cada submódulo, que geralmente é exatamente o que você deseja.

(Isso foi copiado desta resposta .)

Iulian Onofrei
fonte
Se você decidir responder a uma pergunta antiga que tenha respostas bem estabelecidas e corretas, adicionar uma nova resposta no final do dia pode não lhe dar crédito. Se você tiver alguma informação nova e distinta, ou estiver convencido de que as outras respostas estão erradas, adicione uma nova resposta, mas "mais uma resposta" fornecerá a mesma informação básica muito tempo depois que a pergunta for feita normalmente " você ganha muito crédito. Não há explicação sobre o que isso faz - nem mesmo um link para documentação externa (o que não seria suficiente).
perfil completo de Jonathan Leffler
2
Não é "mais uma resposta", pois nenhuma outra resposta possui esse comando (prove que estou errado). Como outras respostas não funcionaram para mim, esse comentário funcionou, por isso decidi publicá-la como resposta, dando crédito ao proprietário original. Portanto, considere remover seu voto negativo.
Iulian Onofrei
Há um comentário de MindTooth de 2015 dizendo que é isso que eles fazem agora. Você não fornece explicações sobre o que isso faz (embora você mencione o MindTooth, mas não há uma explicação real sobre o que você entende por isso - incorporar URLs, como neste comentário, ajudaria). Você não diz por que é uma boa ideia. Você não faz nenhuma ressalva. Esta não é, na minha opinião, uma resposta útil, pois levanta mais perguntas do que resolve.
precisa
1
Com isso, quis dizer que funciona, em vez de não funcionar. Acredite, se mais pessoas vissem essa resposta, ficariam felizes, porque funciona . Para coisas como essa, a maioria das pessoas só quer saber o comando que atualiza um submódulo git, não como ele é implementado.
Iulian Onofrei
Eu editei a resposta para provar que você estava errado, também, stackoverflow.com/questions/1979167/git-submodule-update/… !!!
Iulian Onofrei