Como mover um submódulo Git existente dentro de um repositório Git?

356

Gostaria de alterar o nome do diretório de um sub-módulo Git no meu superprojeto Git.

Vamos supor que eu tenha a seguinte entrada no meu .gitmodules arquivo:

[submodule ".emacs.d/vimpulse"]  
path = .emacs.d/vimpulse  
url = git://gitorious.org/vimpulse/vimpulse.git

O que eu tenho que digitar para mover o .emacs.d/vimpulsediretório .emacs.d/vendor/vimpulsesem excluí-lo primeiro (explicado aqui e aqui ) e depois adicioná-lo novamente.

O Git realmente precisa de todo o caminho na tag submodule

[submodule ".emacs.d/vimpulse"]

ou também é possível armazenar apenas o nome do subprojeto?

[submodule "vimpulse"]
thisch
fonte
NOTA: o OP responde à sua própria pergunta com o git mvcomando, diretamente na pergunta.
precisa saber é o seguinte
No entanto, você não pode usar git mvassim. Use deinitentão rm como stackoverflow.com/a/18892438/8047 especificado .
Dan Rosenstark
14
@ Yar: pelo menos no git 2.0.0, também git mv funciona para sub-módulos, sem necessidade de mais nada.
Pedro Romano
9
Começando com o Git, os 1.8.5sub-módulos móveis são suportados nativamente usando o git mvcomando ( nas notas de versão , primeiro vinculadas pelo próprio @thisch). Também respondeu aqui
dennisschagt 29/11
git mvmove o submódulo na área de trabalho e atualiza os arquivos .git do submódulo corretamente, mas a subpasta dentro da pasta .git / modules do repositório pai permanece a mesma - tudo bem? (Estou usando o git 2.19.0 no Windows)
yoyo

Respostas:

377

Nota: Conforme mencionado nos comentários, esta resposta se refere às etapas necessárias nas versões mais antigas do git. O Git agora tem suporte nativo para mover submódulos:

Desde o git 1.8.5, git mv old/submod new/submodfunciona como esperado e faz todo o encanamento para você. Você pode usar o git 1.9.3 ou mais recente, porque inclui correções para a movimentação do submódulo.


O processo é semelhante a como você removeria um submódulo (consulte Como removo um submódulo? ):

  1. Edite .gitmodulese altere o caminho do submódulo adequadamente e coloque-o no índice comgit add .gitmodules .
  2. Se necessário, crie o diretório pai do novo local do submódulo (mkdir -p new/parent ).
  3. Mova todo o conteúdo do diretório antigo para o novo (mv -vi old/parent/submodule new/parent/submodule ).
  4. Verifique se o Git rastreia este diretório (git add new/parent ).
  5. Remova o diretório antigo com git rm --cached old/parent/submodule .
  6. Mova o diretório .git/modules/old/parent/submodulecom todo o seu conteúdo para .git/modules/new/parent/submodule.
  7. Edite o .git/modules/new/parent/configarquivo, verifique se o item da árvore de trabalho aponta para os novos locais, portanto, neste exemplo deve ser worktree = ../../../../../new/parent/module. Normalmente, deve haver mais de dois ..diretórios no caminho direto nesse local.
  8. Edite o arquivo new/parent/module/.git, verifique se o caminho aponta para o novo local correto dentro da .gitpasta principal do projeto , neste exemplo gitdir: ../../../.git/modules/new/parent/submodule.

    git status saída fica assim para mim depois:

    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #       modified:   .gitmodules
    #       renamed:    old/parent/submodule -> new/parent/submodule
    #
    
  9. Por fim, confirme as alterações.

Axel Beckert
fonte
37
Quando você atualiza .gitmodules, atualize a pathconfiguração e o nome do sub-módulo. Por exemplo, ao mover foo / module para bar / module, você deve alterar em .gitmodules a seção [submodule "foo/module"]para [submodule "bar/module"]e, na mesma seção, path = foo/modulepara path = bar/module. Além disso, você deve alterar em .git / config a seção [submodule "foo/module"]para [submodule "bar/module"].
#
3
Também não funcionou para mim ... a solução mais próxima que encontrei é excluir um submódulo (uma dor) e adicioná-lo novamente em outro local.
Pablo Olmos de Aguilera C.
33
Uma observação muito, muito importante: se você fatal: 'git status --porcelain' failed in...simplesmente excluir quaisquer arquivos ou diretórios .git no submódulo.
antitoxic
19
Parece que este post está faltando algumas etapas, como editar .git/modules/old/parent/submodule, movê-lo para o novo local, atualizar gitdirem old/parent/submodule/.git...
szx 28/13
38
Desde o git 1.8.5, git mv old/submod new/submodfunciona como esperado e faz todo o encanamento para você. Você provavelmente deseja usar o git 1.9.3+ porque inclui correções para a movimentação do submódulo.
Valloric 14/05
232

A resposta mais moderna, tirada do comentário de Valloric acima:

  1. Atualize para o Git 1.9.3 (ou 2.18 se o submódulo contiver submódulos aninhados )
  2. git mv old/submod new/submod
  3. Depois, o .gitmodules e o diretório do submódulo já estão preparados para uma confirmação (você pode verificar isso com git status .)
  4. Confirme as alterações git commite pronto!

Feito!

phatmann
fonte
3
Isso realmente funcionou com 1.9.3 exceção de um submódulo dentro do submódulo movido. Isso precisava de alguma limpeza manual.
Pascal
3
Isso já deve funcionar na versão, 1.8.5conforme descrito nas notas de versão .
dennisschagt
6
Esta resposta deve receber 1000 upvotes, eu quase fiz uma bagunça no meu repositório, executando as etapas descritas acima, realmente o StackOverflow deve ter um caso de uso para esta situação.
MGP
5
Uau, isso funcionou como um encanto (git 1.9.5), eu gostaria que fosse a resposta selecionada.
Alex Ilyaev 22/03/2015
7
Uma coisa que isso não faz é que não altera o rótulo inicial do submódulo. Se você verificar o .gitmodulesarquivo, ele old/submodainda será usado como o rótulo para o submódulo enquanto o caminho foi alterado. Para alterar o rótulo também, parece que você precisa realmente mover o caminho do diretório de módulos para dentro .gite, em seguida, alterar manualmente o rótulo .gitmodules.
precisa saber é o seguinte
55

No meu caso, eu queria mover um sub-módulo de um diretório para um subdiretório, por exemplo, "AFNetworking" -> "ext / AFNetworking". Estes são os passos que segui:

  1. Edite .gitmodules alterando o nome e o caminho do sub-módulo para "ext / AFNetworking"
  2. Mova o diretório git do sub-módulo de ".git / modules / AFNetworking" para ".git / modules / ext / AFNetworking"
  3. Mover a biblioteca de "AFNetworking" para "ext / AFNetworking"
  4. Edite ".git / modules / ext / AFNetworking / config" e corrija a [core] worktreelinha. Mina alterada de ../../../AFNetworkingpara../../../../ext/AFNetworking
  5. Edite "ext / AFNetworking / .git" e corrija gitdir. Mina alterada de ../.git/modules/AFNetworkingpara../../git/modules/ext/AFNetworking
  6. git add .gitmodules
  7. git rm --cached AFNetworking
  8. git submodule add -f <url> ext/AFNetworking

Por fim, vi no status git:

matt$ git status
# On branch ios-master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   .gitmodules
#   renamed:    AFNetworking -> ext/AFNetworking

Et voila. O exemplo acima não altera a profundidade do diretório, o que faz uma grande diferença na complexidade da tarefa e não altera o nome do submódulo (o que pode não ser realmente necessário, mas eu fiz isso para ser consistente com o que aconteceria se eu adicionasse um novo módulo nesse caminho.)

Matt Connolly
fonte
4
Obrigado Matt. Eu estava perdido na resposta aceita. Obrigado por cobrir mais do que o caso base. Isso funcionou como um encanto.
Andrew Hubbs
Você não precisa embaralhar os caminhos .git / modules ou alterar o nome do submódulo (como mencionam arand e Bob Bell). No entanto, isso pode manter as coisas mais limpas.
gatoatigrado 25/03
Não se esqueça de executar as etapas 2, 3, 4 e 5 recursivamente para qualquer sub-módulo.
precisa saber é o seguinte
22

[Atualização: 26/11/2014] Como Yar resume bem abaixo, antes de fazer qualquer coisa, verifique o URL do submódulo. Se desconhecido, abra .git/.gitmodulese examine a chave submodule.<name>.url.

O que funcionou para mim foi remover o antigo submódulo usando git submodule deinit <submodule>seguido por git rm <submodule-folder>. Em seguida, adicione o submódulo novamente com o novo nome da pasta e confirme. A verificação do status do git antes da confirmação mostra o antigo submódulo renomeado para o novo nome e o .gitmodule modificado.

$ git submodule deinit foo
$ git rm foo
$ git submodule add https://bar.com/foo.git new-foo
$ git status
renamed:    foo -> new-foo
modified:   .gitmodules
$ git commit -am "rename foo submodule to new-foo"
Mark Mikofski
fonte
11
Isso requer o git 1.8.3 ou superior. Veja este post para atualizar seu git: evgeny-goldin.com/blog/3-ways-install-git-linux-ubuntu
Michael Cole
11
Ou, uma maneira melhor: ppa sudo add-apt-repositório: / ppa sudo apt-get update git-core sudo apt-get install git
Michael Cole
@MichaelCole Thanks! Você está certo! Veja as notas de versão do Git-1.8.3 . FYI: O Ubuntu-13.10 (Saucy Salamander) possui o Git-1.8.3.2 , mas é bom saber que existe ppa . Além disso, a estratégia de mesclagem de subárvore git do IMHO é uma abordagem melhor; Eu abandonei submódulos para meus próprios projetos. Ainda é bom de entender para projetos existentes.
58578 Mark Mikofski
Eu tentei várias soluções, mas a sua é a melhor. Use apenas a linha de comando para não precisar (e não deve) modificar nenhum arquivo git. Obrigado!
Nahung89 31/07/19
12

O truque parece entender que o .gitdiretório para submódulos agora é mantido no repositório principal, abaixo .git/modules, e cada submódulo possui um .gitarquivo que aponta para ele. Este é o procedimento que você precisa agora:

  • Mova o submódulo para sua nova casa.
  • Edite o .gitarquivo no diretório de trabalho do submódulo e modifique o caminho que ele contém para que aponte para o diretório correto no diretório do repositório principal .git/modules.
  • Digite o .git/modulesdiretório do repositório principal e localize o diretório correspondente ao seu submódulo.
  • Edite o configarquivo, atualizando o worktreecaminho para que ele aponte para o novo local do diretório de trabalho do submódulo.
  • Edite o .gitmodulesarquivo na raiz do repositório principal, atualizando o caminho para o diretório de trabalho do submódulo.
  • git add -u
  • git add <parent-of-new-submodule-directory>(É importante que você adicione o pai , e não o diretório do submodule.)

Algumas notas:

  • As [submodule "submodule-name"]linhas .gitmodulese .git/configdevem coincidir, mas não correspondem a mais nada.
  • O diretório de trabalho e o .gitdiretório do submódulo devem apontar corretamente um para o outro.
  • Os arquivos .gitmodulese .git/configdevem ser sincronizados.
Paul Gideon Dann
fonte
9

A sequência entre aspas após "[submódulo" não importa. Você pode alterá-lo para "foobar", se quiser. É usado para encontrar a entrada correspondente em ".git / config".

Portanto, se você fizer a alteração antes de executar o "git submodule init", funcionará bem. Se você fizer a alteração (ou capturá-la através de uma mesclagem), será necessário editar manualmente .git / config ou executar "git submodule init" novamente. Se você fizer o último, ficará com uma entrada "inativa" inofensiva com o nome antigo em .git / config.

Bob Bell
fonte
Isso é realmente irritante, mas você está certo. A pior parte é que, se você apenas alterar a URL, executar o git init não parece atualizá-lo, você precisará editar o .git / config manualmente.
crimson_penguin
11
neste caso git submodule syncpropaga a alteração para .git/configautomaticamente
charlesb
9

Você pode simplesmente adicionar um novo submódulo e remover o submódulo antigo usando comandos padrão. (deve evitar erros acidentais dentro do .git)

Exemplo de configuração:

mkdir foo; cd foo; git init; 
echo "readme" > README.md; git add README.md; git commit -m "First"
## add submodule
git submodule add git://github.com/jquery/jquery.git
git commit -m "Added jquery"
## </setup example>

Examine a movimentação 'jquery' para 'vendor / jquery / jquery':

oldPath="jquery"
newPath="vendor/jquery/jquery"
orginUrl=`git config --local --get submodule.${oldPath}.url`

## add new submodule
mkdir -p `dirname "${newPath}"`
git submodule add -- "${orginUrl}" "${newPath}"

## remove old submodule
git config -f .git/config --remove-section "submodule.${oldPath}"
git config -f .gitmodules --remove-section "submodule.${oldPath}"
git rm --cached "${oldPath}"
rm -rf "${oldPath}"              ## remove old src
rm -rf ".git/modules/${oldPath}" ## cleanup gitdir (housekeeping)

## commit
git add .gitmodules
git commit -m "Renamed ${oldPath} to ${newPath}"

Método de bônus para submódulos grandes:

Se o submódulo for grande e você preferir não esperar o clone, poderá criar o novo submódulo usando o antigo como origem e, em seguida, alternar a origem.

Exemplo (use o mesmo exemplo de configuração)

oldPath="jquery"
newPath="vendor/jquery/jquery"
baseDir=`pwd`
orginUrl=`git config --local --get submodule.${oldPath}.url`

# add new submodule using old submodule as origin
mkdir -p `dirname "${newPath}"`
git submodule add -- "file://${baseDir}/${oldPath}" "${newPath}"

## change origin back to original
git config -f .gitmodules submodule."${newPath}".url "${orginUrl}"
git submodule sync -- "${newPath}"

## remove old submodule
...
Lance Rushing
fonte
Se você não estiver usando o head, talvez também precise verificar a versão correta do módulo em newPath.
21133 paulmelnikow
2

A solução fornecida não funcionou para mim, no entanto, uma versão semelhante funcionou ...

Isso ocorre com um repositório clonado, portanto, o submodule git repos está contido no repositório superior .git dir. Todos os cátions são do repositório superior:

  1. Edite .gitmodules e altere a configuração "path =" para o submódulo em questão. (Não é necessário alterar o rótulo nem adicionar esse arquivo ao índice.)

  2. Edite .git / modules / name / config e altere a configuração "worktree =" para o submódulo em questão

  3. corre:

    mv submodule newpath/submodule
    git add -u
    git add newpath/submodule
    

Gostaria de saber se faz diferença se os repositórios são atômicos ou submódulos relativos, no meu caso, foi relativo (submódulo / .git é uma ref voltar ao topproject / .git / modules / submódulo)

arand
fonte
2

Basta usar o script de shell git-submodule-move .

Flimm
fonte
Hei, procurei essa pergunta novamente e usei uma das respostas mais votadas, e agora gostaria de rolar para baixo e ver minha resposta anterior da qual havia esquecido.
Flimm
2

Eu acabei de passar por essa provação ontem e essa resposta funcionou perfeitamente. Aqui estão os meus passos, para maior clareza:

  1. Certifique-se de que o submódulo esteja registrado e enviado ao servidor. Você também precisa saber em que ramo está.
  2. Você precisa da URL do seu submódulo! Use more .gitmodulesporque, quando você excluir o submódulo, ele não estará disponível
  3. Agora você pode usar deinit, rme depoissubmodule add

EXEMPLO

COMANDOS

    git submodule deinit Classes/lib/mustIReally
    git rm foo
    git submodule add http://developer.audiob.us/download/SDK.git lib/AudioBus

    # do your normal commit and push
    git commit -a 

NOTA: O git mv não faz isso. Em absoluto.

Dan Rosenstark
fonte
3
Bom resumo. O +1 git mvdeve ser melhor nas últimas versões do Git.
VonC
O @VonC eu testei no git 1.8.5, com certeza é o melhor possível mv. Obrigado!
Dan Rosenstark