Come posso spostare un sottomodulo Git esistente all'interno di un repository Git?


356

Vorrei cambiare il nome della directory di un sottomodulo Git nel mio superprogramma Git.

Supponiamo che io abbia la seguente voce nel mio .gitmodulesfile:

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

Cosa devo digitare per spostare la .emacs.d/vimpulsedirectory .emacs.d/vendor/vimpulsesenza prima eliminarla (spiegata qui e qui ) e quindi aggiungerla di nuovo.

Git ha davvero bisogno dell'intero percorso nel tag submodule

[submodule ".emacs.d/vimpulse"]

o è anche possibile memorizzare solo il nome del sottoprogetto?

[submodule "vimpulse"]

NOTA: l'OP risponde alla propria domanda con il git mvcomando, proprio nella domanda.
Dan Rosenstark,

TUTTAVIA, non puoi usare git mvcosì. Utilizzare deinitquindi rm come specificato stackoverflow.com/a/18892438/8047 .
Dan Rosenstark,

14
@Yar: almeno su git 2.0.0, git mv funziona anche con i sottomoduli, senza bisogno di nient'altro.
Pedro Romano,

9
A partire da Git lo 1.8.5spostamento dei sottomoduli è supportato in modo nativo usando il git mvcomando ( dalle note di rilascio , prima collegate dallo stesso @thisch). Anche risposto qui
dennisschagt,

git mvsposta il sottomodulo nell'area di lavoro e aggiorna correttamente i file .git del sottomodulo, ma la sottocartella all'interno della cartella .git / modules del repository padre rimane la stessa - va bene? (Sto usando git 2.19.0 su Windows)
yoyo

Risposte:


377

Nota: come menzionato nei commenti, questa risposta si riferisce ai passaggi necessari con le versioni precedenti di git. Git ora ha il supporto nativo per lo spostamento dei sottomoduli:

Da git 1.8.5, git mv old/submod new/submodfunziona come previsto e fa tutto l'impianto idraulico per te. Potresti voler usare git 1.9.3 o più recenti, perché include correzioni per lo spostamento dei sottomoduli.


Il processo è simile a come rimuoveresti un sottomodulo (vedi Come rimuovo un sottomodulo? ):

  1. Modifica .gitmodulese modifica il percorso del sottomodulo in modo appropriato e inseriscilo nell'indice con git add .gitmodules.
  2. Se necessario, creare la directory principale della nuova posizione del sottomodulo ( mkdir -p new/parent).
  3. Sposta tutto il contenuto dalla vecchia alla nuova directory ( mv -vi old/parent/submodule new/parent/submodule).
  4. Assicurati che Git segua questa directory ( git add new/parent).
  5. Rimuovere la vecchia directory con git rm --cached old/parent/submodule.
  6. Sposta la directory .git/modules/old/parent/submodulecon tutto il suo contenuto in .git/modules/new/parent/submodule.
  7. Modifica il .git/modules/new/parent/configfile, assicurati che l'elemento worktree punti verso le nuove posizioni, quindi in questo esempio dovrebbe essere worktree = ../../../../../new/parent/module. In genere ci dovrebbero essere due più ..di directory nel percorso diretto in quel luogo.
  8. Modifica il file new/parent/module/.git, assicurati che il percorso in esso punti nella nuova posizione corretta all'interno della .gitcartella principale del progetto , quindi in questo esempio gitdir: ../../../.git/modules/new/parent/submodule.

    git status l'output appare così per me in seguito:

    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #       modified:   .gitmodules
    #       renamed:    old/parent/submodule -> new/parent/submodule
    #
    
  9. Infine, esegui il commit delle modifiche.


37
Quando aggiorni .gitmodules assicurati di aggiornare sia quella pathconfigurazione che il nome del sottomodulo. Ad esempio, nel muoversi foo / modulo bar / modulo è necessario modificare nel .gitmodules sezione [submodule "foo/module"]a [submodule "bar/module"], e sotto quella stessa sezione path = foo/modulea path = bar/module. Inoltre, è necessario modificare in .git / config la sezione [submodule "foo/module"]in [submodule "bar/module"].
Wilhelmtell,

3
Neanche per me ha funzionato ... la soluzione più vicina che ho trovato è l'eliminazione di un sottomodulo (una seccatura) e quindi aggiungerlo di nuovo in un'altra posizione.
Pablo Olmos de Aguilera C.

33
Una nota molto importante: se ottieni fatal: 'git status --porcelain' failed in...solo file o directory .git nel sottomodulo.
antitossico

19
Sembra che questo post manchi alcuni passaggi, come la modifica .git/modules/old/parent/submodule, lo spostamento nella nuova posizione, l'aggiornamento gitdirin old/parent/submodule/.git...
szx

38
Da git 1.8.5, git mv old/submod new/submodfunziona come previsto e fa tutto l'impianto idraulico per te. Probabilmente vuoi usare git 1.9.3+ perché include correzioni per lo spostamento dei sottomoduli.
Valloric,

232

La risposta più moderna, tratta dal commento di Valloric sopra:

  1. Esegui l'upgrade a Git 1.9.3 (o 2.18 se il sottomodulo contiene sottomoduli annidati )
  2. git mv old/submod new/submod
  3. Successivamente, i .gitmodules e la directory del sottomodulo sono già in scena per un commit (è possibile verificarlo con git status.)
  4. Impegna i cambiamenti con git commite sei a posto!

Fatto!


3
Ciò ha funzionato davvero con l' 1.9.3 eccezione di un sottomodulo all'interno del sottomodulo spostato. Ci voleva un po 'di pulizia manuale.
Pascal,

3
Questo dovrebbe già funzionare nella versione 1.8.5descritta nelle note di rilascio .
dennisschagt,

6
Questa risposta dovrebbe ottenere 1000 voti positivi, ho quasi fatto un casino con il mio repository facendo i passaggi sopra descritti, davvero StackOverflow dovrebbe avere un caso d'uso per questa situazione.
MGP,

5
Wow, ha funzionato come un incantesimo (git 1.9.5), vorrei che fosse la risposta selezionata.
Alex Ilyaev,

7
Una cosa che non fa è che non cambia l'etichetta iniziale per il sottomodulo. Se si controlla il .gitmodulesfile, old/submodverrà comunque utilizzato come etichetta per il sottomodulo mentre il percorso è stato modificato. Per cambiare anche l'etichetta, sembra che sia necessario spostare effettivamente il percorso della directory dei moduli all'interno .git, quindi cambiare manualmente l'etichetta .gitmodules.
CMCDragonkai,

55

Nel mio caso, volevo spostare un sottomodulo da una directory in una sottodirectory, ad esempio "AFNetworking" -> "ext / AFNetworking". Questi sono i passaggi che ho seguito:

  1. Modifica i moduli .git cambiando il nome e il percorso del sottomodulo in "ext / AFNetworking"
  2. Spostare la directory git del sottomodulo da ".git / modules / AFNetworking" a ".git / modules / ext / AFNetworking"
  3. Sposta la libreria da "AFNetworking" a "ext / AFNetworking"
  4. Modifica ".git / modules / ext / AFNetworking / config" e correggi la [core] worktreelinea. Il mio è cambiato da ../../../AFNetworkinga../../../../ext/AFNetworking
  5. Modifica "ext / AFNetworking / .git" e correggi gitdir. Il mio è cambiato da ../.git/modules/AFNetworkinga../../git/modules/ext/AFNetworking
  6. git add .gitmodules
  7. git rm --cached AFNetworking
  8. git submodule add -f <url> ext/AFNetworking

Alla fine, ho visto lo stato 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 voilà. L'esempio sopra non cambia la profondità della directory, il che fa una grande differenza per la complessità dell'attività e non cambia il nome del sottomodulo (che potrebbe non essere realmente necessario, ma l'ho fatto per essere coerente con ciò che accadrebbe se avessi aggiunto un nuovo modulo in quel percorso.)


4
Grazie Matt. Mi ero perso sulla risposta accettata. Grazie per coprire più del caso base. Questo ha funzionato come un fascino.
Andrew Hubbs,

Non è necessario mescolare i percorsi .git / modules o cambiare il nome del sottomodulo (come menzionano arand e Bob Bell). Tuttavia, farlo potrebbe mantenere le cose più pulite.
gatoatigrado,

Non dimenticare di eseguire i passaggi 2, 3, 4 e 5 in modo ricorsivo per tutti i sottomoduli.
Herzbube,

22

[Aggiornamento: 26-11-2014] Mentre Yar riassume bene di seguito, prima di fare qualsiasi cosa, assicurati di conoscere l'URL del sottomodulo. Se sconosciuto, aprire .git/.gitmodulesed esaminare la chiave submodule.<name>.url.

Quello che ha funzionato per me è stato rimuovere il vecchio sottomodulo usando git submodule deinit <submodule>seguito da git rm <submodule-folder>. Quindi aggiungere nuovamente il sottomodulo con il nuovo nome della cartella e confermare. Il controllo dello stato di git prima del commit mostra il vecchio sottomodulo rinominato con il nuovo nome e modificato .gitmodule.

$ 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"

1
Ciò richiede git 1.8.3 o versioni successive. Vedi questo post per aggiornare git: evgeny-goldin.com/blog/3-ways-install-git-linux-ubuntu
Michael Cole

1
Oppure, un modo migliore: sudo add-apt-repository ppa: git-core / ppa sudo apt-get update sudo apt-get install git
Michael Cole

@MichaelCole Grazie! Hai ragione! Vedi le Note di rilascio di Git-1.8.3 . Cordiali saluti: Ubuntu-13.10 (Saucy Salamander) ha Git-1.8.3.2 , ma è bello sapere che c'è ppa . Inoltre, la strategia di unione di sottotree git IMHO è un approccio migliore; Ho abbandonato i sottomoduli per i miei progetti. Ancora buono da capire per i progetti esistenti.
Mark Mikofski,

Ho provato diverse soluzioni ma la tua è la migliore. Usa solo la riga di comando in modo da non dover (e non dovresti) modificare alcun file git. Grazie!
nahung89

12

Il trucco sembra comprendere che la .gitdirectory per i sottomoduli è ora mantenuta nel repository principale, sotto .git/modules, e ogni sottomodulo ha un .gitfile che lo punta. Questa è la procedura che ti serve ora:

  • Sposta il sottomodulo nella sua nuova casa.
  • Modificare il .gitfile nella directory di lavoro del sottomodulo e modificare il percorso in esso contenuto in modo che punti alla directory corretta nella directory del repository principale .git/modules.
  • Immettere la .git/modulesdirectory del repository principale e trovare la directory corrispondente al proprio sottomodulo.
  • Modifica il configfile, aggiornando il worktreepercorso in modo che punti alla nuova posizione della directory di lavoro del sottomodulo.
  • Modificare il .gitmodulesfile nella radice del repository principale, aggiornando il percorso nella directory di lavoro del sottomodulo.
  • git add -u
  • git add <parent-of-new-submodule-directory>(È importante aggiungere il genitore e non la directory del sottomodulo stesso.)

Alcune note:

  • Le [submodule "submodule-name"]linee in .gitmodulese .git/configdevono corrispondere a vicenda, ma non corrispondono a qualsiasi altra cosa.
  • La directory di lavoro del sottomodulo e la .gitdirectory devono puntare correttamente l'una verso l'altra.
  • I file .gitmodulese .git/configdevono essere sincronizzati.

9

La stringa tra virgolette dopo "[sottomodulo" non ha importanza. Puoi cambiarlo in "foobar" se vuoi. È usato per trovare la voce corrispondente in ".git / config".

Pertanto, se apporti la modifica prima di eseguire "git submodule init", funzionerà correttamente. Se apporti la modifica (o raccogli la modifica tramite un'unione), dovrai modificare manualmente .git / config o eseguire nuovamente "git submodule init". Se fai quest'ultima, ti verrà lasciata una voce "incagliata" innocua con il vecchio nome in .git / config.


Questo è davvero fastidioso, ma hai ragione. La parte peggiore è che, se si modifica semplicemente l'URL, l'esecuzione di git init non sembra aggiornarlo, è necessario modificare manualmente .git / config.
crimson_penguin,

1
in questo caso git submodule syncpropaga .git/configautomaticamente la modifica
CharlesB,

9

Puoi semplicemente aggiungere un nuovo sottomodulo e rimuovere il vecchio sottomodulo usando i comandi standard. (dovrebbe prevenire eventuali errori accidentali all'interno di .git)

Esempio di installazione:

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>

Sposta l'esempio "jquery" su "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}"

Metodo bonus per sottomoduli di grandi dimensioni:

Se il sottomodulo è di grandi dimensioni e si preferisce non attendere il clone, è possibile creare il nuovo sottomodulo utilizzando il vecchio come origine, quindi cambiare l'origine.

Esempio (utilizzare la stessa configurazione di esempio)

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
...

Se non si utilizza head, potrebbe essere necessario verificare anche la versione corretta del modulo su newPath.
paulmelnikow,

2

La soluzione fornita non ha funzionato per me, tuttavia una versione simile ha funzionato ...

Questo è con un repository clonato, quindi i repository git del sottomodulo sono contenuti nei repository principali .git dir. Tutti i cationi provengono dal repository superiore:

  1. Modifica .gitmodules e modifica l'impostazione "path =" per il sottomodulo in questione. (Non è necessario modificare l'etichetta né aggiungere questo file all'indice.)

  2. Modifica .git / modules / name / config e modifica l'impostazione "worktree =" per il sottomodulo in questione

  3. correre:

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

Mi chiedo se fa differenza se i repository sono atomici o relativi sottomoduli, nel mio caso era relativo (sottomodule / .git è un riferimento a topproject / .git / modules / submodule)


2

Usa semplicemente lo script shell git-submodule-move .


Heh, ho cercato di nuovo questa domanda, e ho usato una delle risposte più votate, e ora vorrei che avessi scorrere verso il basso e visto la mia risposta precedente che avevo dimenticato.
Flimm,

2

Ieri ho appena superato questa prova e questa risposta ha funzionato perfettamente. Ecco i miei passi, per chiarezza:

  1. Assicurarsi che il sottomodulo sia archiviato e inviato al suo server. Devi anche sapere su quale ramo si trova.
  2. Hai bisogno dell'URL del tuo sottomodulo! Utilizzare more .gitmodulesperché una volta eliminato il sottomodulo non ci sarà più
  3. Ora è possibile utilizzare deinit, rme poisubmodule add

ESEMPIO

COMANDI

    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: git mv non lo fa. Affatto.


3
Buon riassunto. git mvTuttavia, +1 dovrebbe essere migliore nelle ultime versioni di Git.
VonC,

@VonC Ho testato su git 1.8.5, abbastanza sicuro che sia buono come dovrebbe mv. Grazie!
Dan Rosenstark,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.