Como posso especificar uma ramificação / tag ao adicionar um submódulo Git?

756

Como git submodule add -bfunciona?

Após adicionar um submódulo com uma ramificação específica, um novo repositório clonado (após git submodule update --init) estará em uma consolidação específica, não a ramificação propriamente dita ( git statusno submódulo mostra "Atualmente não está em nenhuma ramificação").

Não consigo encontrar nenhuma informação sobre .gitmodulesou .git/configsobre a ramificação do submódulo ou qualquer confirmação específica, então como o Git descobre isso?

Além disso, é possível especificar uma tag em vez de uma ramificação?

Estou usando a versão 1.6.5.2.

Ivan
fonte
3
Se você tem um existente submodule que não está seguindo um ramo ainda , mas você deseja que ele agora iria acompanhar um ramo ... ver minha resposta abaixo
VonC

Respostas:

745

Nota: O Git 1.8.2 adicionou a possibilidade de rastrear ramificações. Veja algumas das respostas abaixo.


É um pouco confuso se acostumar com isso, mas os submódulos não estão em um ramo. Eles são, como você diz, apenas um ponteiro para um commit específico do repositório do submódulo.

Isso significa que, quando alguém faz check-out no seu repositório, ou extrai seu código e faz a atualização do sub-módulo git, o sub-módulo é retirado do check-out para esse commit específico.

Isso é ótimo para um submódulo que não muda com frequência, porque todos no projeto podem ter o submódulo no mesmo commit.

Se você deseja mover o submódulo para uma tag específica:

cd submodule_directory
git checkout v1.0
cd ..
git add submodule_directory
git commit -m "moved submodule to v1.0"
git push

Em seguida, outro desenvolvedor que deseja ter submodule_directory alterado para essa tag, faz isso

git pull
git submodule update --init

git pullalterações às quais confirmam seus diretórios de submodule. git submodule updatena verdade mescla o novo código.

djacobs7
fonte
8
Essa é uma explicação muito boa, obrigado! E, claro, depois de ler sua resposta, percebi que o commit é salvo dentro do próprio submódulo (submódulo / .git / HEAD).
Ivan
4
Isso não parece funcionar no git 1.7.4.4. cd my_submodule; git checkout [ref in submodule's repositoryrendimentos fatal: reference is not a tree: .... É como se gitapenas operasse no repositório pai.
James A. Rosen
3
É bom usar submodules git mesmo para projetos que são atualizados com frequência. O kernel do Linux usa-lo e ele não é tão ruim
10
É git checkout v1.0um ramo ou uma etiqueta?
Bernhard Döbler
8
Considere uma tag como um alias legível por humanos para um commit. E uma confirmação é um conjunto de estados específicos para cada arquivo. Uma ramificação é essencialmente a mesma coisa, exceto que você pode fazer alterações nela.
deadbabykitten
657

Gostaria de adicionar uma resposta aqui que é realmente apenas um conglomerado de outras respostas, mas acho que pode ser mais completa.

Você sabe que possui um submódulo Git quando possui essas duas coisas.

  1. Você .gitmodulestem uma entrada assim:

    [submodule "SubmoduleTestRepo"]
        path = SubmoduleTestRepo
        url = https://github.com/jzaccone/SubmoduleTestRepo.git
    
  2. Você tem um objeto submodule (chamado SubmoduleTestRepo neste exemplo) em seu repositório Git. O GitHub mostra esses objetos como "submódulo". Ou faça a git submodule statuspartir de uma linha de comando. Os objetos do submódulo Git são tipos especiais de objetos Git e mantêm as informações do SHA para uma confirmação específica.

    Sempre que você fizer um git submodule update, ele preencherá seu submódulo com o conteúdo da confirmação. Ele sabe onde encontrar o commit por causa das informações no .gitmodules.

    Agora, tudo o que -bfaz é adicionar uma linha no seu .gitmodulesarquivo. Então, seguindo o mesmo exemplo, ficaria assim:

    [submodule "SubmoduleTestRepo"]
        path = SubmoduleTestRepo
        url = https://github.com/jzaccone/SubmoduleTestRepo.git
        branch = master
    

    Nota: apenas o nome da ramificação é suportado em um .gitmodulesarquivo, mas SHA e TAG não são suportados! (em vez disso, o commit da ramificação de cada módulo pode ser rastreado e atualizado usando " git add .", por exemplo git add ./SubmoduleTestRepo, e você não precisa alterar o .gitmodulesarquivo todas as vezes)

    O objeto submodule ainda está apontando para uma confirmação específica. A única coisa que a -bopção compra é a capacidade de adicionar um --remotesinalizador à sua atualização de acordo com a resposta de Vogella:

    git submodule update --remote
    

    Em vez de preencher o conteúdo do submódulo para o commit apontado pelo submódulo, ele substitui esse commit pelo último commit no branch master, ENTÃO ele preenche o submódulo com esse commit. Isso pode ser feito em duas etapas pela resposta djacobs7. Como você atualizou o commit que o objeto do sub-módulo está apontando, você deve confirmar o objeto do sub-módulo alterado no seu repositório Git.

    git submodule add -bnão é uma maneira mágica de manter tudo atualizado com uma filial. Simplesmente adiciona informações sobre uma ramificação no .gitmodulesarquivo e oferece a opção de atualizar o objeto submódulo para a confirmação mais recente de uma ramificação especificada antes de preenchê-lo.

Johnny Z
fonte
14
Esta resposta deve ter mais votos positivos. Eu tenho lido muitas postagens nos últimos dias e isso esclarece toda a confusão. Vindo do mundo SVN e usando externos - alguém quer acreditar que o rastreamento de ramificação do submódulo git mantém magicamente tudo atualizado da ramificação - mas isso não é verdade! Você precisa atualizá-los explicitamente! Como você mencionou, você deve confirmar objetos de sub-módulo alterados.
dtmland
12
Esse rastreamento de ramificação também funciona com tags ? Em vez de uma ramificação, especifiquei uma tag no meu .gitmodulese, após isso $ git submodule update --init --remote TestModule, recebi um erro dizendo: fatal: Needed a single revisione Unable to find current origin/TestTag revision in submodule path 'TestModule'. Ao fazê-lo com um ramo real, ele funciona. Existe uma maneira de especificar uma tag .gitmodulessem precisar especificar a confirmação exata?
Hhut
5
Isso não parece funcionar. Atualizei o hash .gitmodulese corri git submodule updatee nada aconteceu?
precisa saber é o seguinte
2
De alguma forma, isso não funciona para mim. Com um SHA Commit ID, eu sempre obter um erro "Não é possível encontrar revisão atual (eu dobro verificado o número de revisão da cabeça e sua correta) No entanto, se eu usar mestre ele funciona..
infoclogged
2
Inserir um SHA no atributo branch também não funciona para mim. Esse uso também é não suportado pelos docs: git-scm.com/docs/gitmodules
Jakub Bochenski
340

(Git 2.22, Q2 2019, lançado git submodule set-branch --branch aBranch -- <submodule_path>)

Observe que se você possui um submódulo existente que ainda não está rastreando uma ramificação , então ( se você tiver o git 1.8.2+ ):

  • Verifique se o repositório pai sabe que seu submódulo agora rastreia uma ramificação:

    cd /path/to/your/parent/repo
    git config -f .gitmodules submodule.<path>.branch <branch>
    
  • Verifique se o seu submódulo é realmente o mais tardar nesse ramo:

    cd path/to/your/submodule
    git checkout -b branch --track origin/branch
      # if the master branch already exist:
      git branch -u origin/master master
    

         (com 'origin' sendo o nome do repositório remoto upstream do qual o submódulo foi clonado.
         Uma parte git remote -vinterna desse submódulo o exibirá. Geralmente, é 'origin')

  • Não se esqueça de registrar o novo estado do seu submódulo no repositório pai:

    cd /path/to/your/parent/repo
    git add path/to/your/submodule
    git commit -m "Make submodule tracking a branch"
    
  • A atualização subsequente para esse submódulo precisará usar a --remoteopção:

    # update your submodule
    # --remote will also fetch and ensure that
    # the latest commit from the branch is used
    git submodule update --remote
    
    # to avoid fetching use
    git submodule update --remote --no-fetch 
    

Observe que, com o Git 2.10+ (terceiro trimestre de 2016), você pode usar ' .' como um nome de filial:

O nome do ramo é registrada como submodule.<name>.branchem .gitmodulespara update --remote.
Um valor especial de .é usado para indicar que o nome da ramificação no submódulo deve ser o mesmo nome que a ramificação atual no repositório atual .

Mas, como comentado por LubosD

Com git checkout, se o nome do ramo a seguir for " .", ele matará seu trabalho não confirmado!
Use em git switchvez disso.

Isso significa Git 2.23 (agosto de 2019) ou mais.

Consulte " Confundido porgit checkout "


Se você deseja atualizar todos os seus submódulos seguindo uma ramificação:

    git submodule update --recursive --remote

Observe que o resultado, para cada submódulo atualizado, quase sempre será um HEAD desanexado , como Dan Cameron observou em sua resposta .

( Clintm observa nos comentários que, se você executar git submodule update --remotee o sha1 resultante for o mesmo que o ramo em que o submódulo está atualmente, ele não fará nada e deixará o submódulo ainda "nesse ramo" e não no estado principal desanexado. )

Para garantir que o ramo seja realmente retirado (e que não modifique o SHA1 da entrada especial que representa o submódulo do repositório pai), ele sugere:

git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; git switch $branch'

Cada submódulo ainda fará referência ao mesmo SHA1, mas se você fizer novos commit, poderá empurrá-los porque eles serão referenciados pela ramificação que você deseja que o submódulo rastreie.
Após esse envio dentro de um submódulo, não se esqueça de voltar ao repositório pai, adicionar, confirmar e enviar o novo SHA1 para esses submódulos modificados.

Observe o uso de $toplevel, recomendado nos comentários de Alexander Pogrebnyak .
$toplevelfoi introduzido no git1.7.2 em maio de 2010: commit f030c96 .

ele contém o caminho absoluto do diretório de nível superior (onde .gitmodulesestá).

dtmlandadiciona nos comentários :

O script foreach falhará ao fazer o check-out de submódulos que não seguem uma ramificação.
No entanto, este comando fornece os dois:

 git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; [ "$branch" = "" ] && git checkout master || git switch $branch' –

O mesmo comando, mas mais fácil de ler:

git submodule foreach -q --recursive \
    'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; \
     [ "$branch" = "" ] && \
     git checkout master || git switch $branch' –

umläute refina o comando do dtmland com uma versão simplificada nos comentários :

git submodule foreach -q --recursive 'git switch $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'

várias linhas:

git submodule foreach -q --recursive \
  'git switch \
  $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'

Antes do Git 2.26 (primeiro trimestre de 2020), uma busca orientada a buscar atualizações recursivamente nos submódulos inevitavelmente produz resmas de saída, e fica difícil identificar mensagens de erro.

O comando foi ensinado a enumerar submódulos que apresentavam erros no final da operação .

Veja commit 0222540 (16 de janeiro de 2020) por Emily Shaffer ( nasamuffin) .
(Incorporado por Junio ​​C Hamano - gitster- in commit b5c71cc , 5 de fevereiro de 2020)

fetch: enfatizar a falha durante a busca do submódulo

Assinado por: Emily Shaffer

Nos casos em que uma busca de submódulo falha quando há muitos submódulos, o erro da busca de submódulo com falha única é ocultado sob atividade nos outros submódulos se mais de uma busca for ativada novamente fetch-by-oid.
Chame uma falha tarde para que o usuário saiba que algo deu errado e onde .

Porque fetch_finish()só é chamado de forma síncrona por run_processes_parallel,mutexing não é necessário submodules_with_errors.

VonC
fonte
1
Pergunta: se eu tiver a pasta subModule1 e desejar rastrear a ramificação principal, o comando resultante ficaria assim: git config -f .gitmodules submodule.subModule1.branch master
BraveNewMath 17/13
1
O foreachscript não dependerá do código codificado <path>, se você substituir <path>por $toplevel/.
Alexander Pogrebnyak 27/11
1
O foreachscript falhará ao fazer o check-out de submódulos que não seguem uma ramificação. No entanto, este comando fornece os dois:git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; [ "$branch" = "" ] && git checkout master || git checkout $branch'
dtmland
2
aqui está uma versão simplificada do script de @ dtmland:git submodule foreach -q --recursive 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'
umläute 15/10/2015
1
Ohh! Na verdade, o script foreach é desnecessário. Temos que executar a atualização do submódulo com a opção --merge ou --rebase: git submodule update --remote --mergeou git submodule update --remote --rebase. Esses comandos fazem o rastreamento da ramificação remota.
precisa saber é o seguinte
206

O Git 1.8.2 adicionou a possibilidade de rastrear ramificações.

# add submodule to track master branch
git submodule add -b branch_name URL_to_Git_repo optional_directory_rename

# update your submodule
git submodule update --remote 

Veja também submódulos Git

vogella
fonte
4
Isso também se aplica a tags?
21430 ThorSummoner
1
Como a adição do submódulo dessa maneira reflete no .gitmodulesarquivo?
21814 Eugene
1
Obrigado Eu apenas usei as informações para me ajudar a criar uma pasta de submódulo sincronizada com um site gh-pages do GitHub: exemplo completo em github.com/o2platform/fluentnode/issues/22
Dinis Cruz
4
Você pode bloquear a uma tag com git submodule add -b tags/<sometag> <url>o qual você pode ver como a linha branch = tags/<sometag>em.gitmodules
KCD
9
@KCD Qual versão do git pode fazer isso com tags. O meu não funciona?
precisa saber é o seguinte
58

Um exemplo de como eu uso os submódulos do Git.

  1. Crie um novo repositório
  2. Em seguida, clone outro repositório como um submódulo
  3. Então nós temos que o submódulo use uma tag chamada V3.1.2
  4. E então nos comprometemos.

E isso se parece um pouco com isso:

git init 
vi README
git add README
git commit 
git submodule add git://github.com/XXXXX/xxx.yyyy.git stm32_std_lib
git status

git submodule init
git submodule update

cd stm32_std_lib/
git reset --hard V3.1.2 
cd ..
git commit -a

git submodule status 

Talvez ajude (mesmo que eu use uma tag e não um ramo)?

Johan
fonte
4
É basicamente a mesma resposta que djacobs7, mas obrigado de qualquer maneira :)
Ivan
1
Você deve conseguir alterar depois da sua git reset --hard V3.1.2? Acabei de receber um "nada a confirmar" com um git statusdo diretório pai.
Nick Radford
1
@ Ivan: Você poderia explicar como isso é o mesmo que a resposta do djacobs7? Até onde eu vejo, a resposta dele nem inclui o comando 'submodule add'; em vez disso, o repositório é adicionado diretamente, sem nenhum link para o repositório git original do módulo. Pelo menos quando tentei essa abordagem, não havia link nos módulos .git.
Michel Müller
A resposta de djacobs7 não inclui toda a explicação, começando com a adição do submódulo. Ele assume que você já o possui.
codemonkey
não apenas adiciona todo o conteúdo do submódulo como objetos rastreados ao seu repositório principal?
user1312695 30/04
38

Na minha experiência, alternar ramificações no superprojeto ou nos checkouts futuros ainda causará CAUSAS desmembradas dos submódulos, independentemente de o submódulo ser adicionado e rastreado adequadamente (por exemplo, respostas @ djacobs7 e @Johnny Z).

E, em vez de verificar manualmente a ramificação correta manualmente ou por meio de um sub-módulo git de script, pode-se usar cada um.

Isso verificará o arquivo de configuração do sub-módulo para a propriedade branch e fará check-out do branch set.

git submodule foreach -q --recursive 'branch="$(git config -f <path>.gitmodules submodule.$name.branch)"; git checkout $branch'

Dan Cameron
fonte
Agradável. +1. Eu incluí o seu comando na minha resposta .
VonC
33

Os submódulos do Git são um pouco estranhos - eles sempre estão no modo "cabeça desanexada" - não são atualizados para o commit mais recente em um ramo, como você poderia esperar.

Isso faz algum sentido quando você pensa sobre isso, no entanto. Digamos que eu crie um repositório foo com a barra do submódulo . Eu envio minhas alterações e digo para você conferir o commit a7402be do repositório foo .

Imagine que alguém comete uma alteração na barra do repositório antes que você possa fazer seu clone.

Quando você faz o check-out do commit a7402be do repositório foo , espera obter o mesmo código que enviei. É por isso que os submódulos não são atualizados até que você diga explicitamente e faça um novo commit.

Pessoalmente, acho que os submódulos são a parte mais confusa do Git. Existem muitos lugares que podem explicar melhor os submódulos do que eu. Eu recomendo o Pro Git de Scott Chacon.

Neall
fonte
Acho que está na hora de começar a ler alguns livros sobre git, obrigado pela recomendação.
Ivan
Desculpe, mas você não esclareceu se alguém obteria o mesmo que você empurrou para o a7402be ou obter o último bar, apesar de sua versão do foo. Obrigado :)
mmm
6
O problema é que deve haver uma opção para dizer "mantenha este submódulo na ramificação X" para que, se você quiser que ele se atualize automaticamente, faça isso acontecer. Isso tornaria os submódulos muito mais úteis para gerenciar, por exemplo, uma instalação do WordPress em que os plugins são todos os repositórios Git sem ter que salvar novamente o superprojeto para cada plug-in que é atualizado.
jerclarke
@jeremyclark git clone git://github.com/git/git.gite empurre esse recurso ...? = D
Alastair
1
A parte mais confusa do Git é que, mesmo depois de mais de uma década de desenvolvimento, uma ferramenta destinada a me ajudar a realizar meu trabalho ainda tem uma experiência do usuário tão ruim e, por razões completamente além de mim, as pessoas gostam de ser mostradas com o dedo pelo Git. A Hora.
0xC0000022L
20

Para alternar ramificação para um submódulo (supondo que você já tenha o submódulo como parte do repositório):

  • cd raiz do seu repositório que contém os submódulos
  • Aberto .gitmodulespara edição
  • Adicione a linha abaixo path = ...e url = ...diga branch = your-branch: para cada submódulo; salvar arquivo .gitmodules.
  • então, sem alterar o diretório, faça $ git submodule update --remote

... isso deve receber as confirmações mais recentes na ramificação especificada, para cada submódulo assim modificado.

Engenheiro
fonte
10

Eu tenho isso no meu arquivo .gitconfig. Ainda é um rascunho, mas provou ser útil a partir de agora. Isso me ajuda a sempre recolocar os submódulos em suas ramificações.

[alias]

######################
#
#Submodules aliases
#
######################


#git sm-trackbranch : places all submodules on their respective branch specified in .gitmodules
#This works if submodules are configured to track a branch, i.e if .gitmodules looks like :
#[submodule "my-submodule"]
#   path = my-submodule
#   url = [email protected]/my-submodule.git
#   branch = my-branch
sm-trackbranch = "! git submodule foreach -q --recursive 'branch=\"$(git config -f $toplevel/.gitmodules submodule.$name.branch)\"; git checkout $branch'"

#sm-pullrebase :
# - pull --rebase on the master repo
# - sm-trackbranch on every submodule
# - pull --rebase on each submodule
#
# Important note :
#- have a clean master repo and subrepos before doing this !
#- this is *not* equivalent to getting the last committed 
#  master repo + its submodules: if some submodules are tracking branches 
#  that have evolved since the last commit in the master repo,
#  they will be using those more recent commits !
#
#  (Note : On the contrary, git submodule update will stick 
#to the last committed SHA1 in the master repo)
#
sm-pullrebase = "! git pull --rebase; git submodule update; git sm-trackbranch ; git submodule foreach 'git pull --rebase' "

# git sm-diff will diff the master repo *and* its submodules
sm-diff = "! git diff && git submodule foreach 'git diff' "

#git sm-push will ask to push also submodules
sm-push = push --recurse-submodules=on-demand

#git alias : list all aliases
#useful in order to learn git syntax
alias = "!git config -l | grep alias | cut -c 7-"
Pascal T.
fonte
3

Nós usamos o Quack para extrair um módulo específico de outro repositório Git. Precisamos extrair código sem toda a base de código do repositório fornecido - precisamos de um módulo / arquivo muito específico desse enorme repositório e deve ser atualizado sempre que executarmos a atualização.

Então, conseguimos isso desta maneira:

Criar configuração

name: Project Name

modules:
  local/path:
    repository: https://github.com/<username>/<repo>.git
    path: repo/path
    branch: dev
  other/local/path/filename.txt:
    repository: https://github.com/<username>/<repo>.git
    hexsha: 9e3e9642cfea36f4ae216d27df100134920143b9
    path: repo/path/filename.txt

profiles:
  init:
    tasks: ['modules']

Com a configuração acima, ele cria um diretório a partir do repositório GitHub fornecido, conforme especificado na configuração do primeiro módulo, e o outro é extrair e criar um arquivo a partir do repositório fornecido.

Outros desenvolvedores só precisam executar

$ quack

E ele extrai o código das configurações acima.

Love Sharma
fonte
2

O único efeito de escolher uma ramificação para um submódulo é que, sempre que você passar o --remote opção na git submodule updatelinha de comando, o Git fará check-out no modo HEAD desanexado (se o --checkoutcomportamento padrão for selecionado) a confirmação mais recente dessa ramificação remota selecionada .

Você deve ter um cuidado especial ao usar esse recurso de rastreamento remoto de ramificação para sub-módulos Git se trabalhar com clones rasos de sub-módulos. A ramificação escolhida para esse fim nas configurações do submódulo NÃO É aquela que será clonada durante git submodule update --remote. Se você também passar o --depthparâmetro e não instruir o Git sobre qual ramificação você deseja clonar - e na verdade você não pode na git submodule updatelinha de comando !! -, ele implicitamente se comportará como explicado na git-clone(1)documentação para git clone --single-branchquando o --branchparâmetro explícito estiver ausente e, portanto , clonará apenas o ramo primário .

Sem surpresa, após o estágio de clone executado pelo git submodule updatecomando, ele finalmente tentará verificar a confirmação mais recente do ramo remoto que você configurou anteriormente para o submódulo e, se esse não for o principal , não fará parte do processo. seu clone raso local e, portanto, falhará com

fatal: precisava de uma única revisão

Não foi possível encontrar a origem atual / revisão de NotThePrimaryBranch no caminho do submódulo 'mySubmodule'

LuKePicci
fonte
como corrigir o erro - precisava de uma única revisão?
NidhinSPradeep
-1

sub-módulo git add -b develop --name branch-name - https: //branch.git

Passiondroid
fonte