Wie verschiebe ich ein vorhandenes Git-Submodul in ein Git-Repository?

356

Ich möchte den Verzeichnisnamen eines Git-Submoduls in meinem Git-Superprojekt ändern.

Nehmen wir an, ich habe den folgenden Eintrag in meiner .gitmodulesDatei:

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

Was muss ich eingeben, um das .emacs.d/vimpulseVerzeichnis zu verschieben, .emacs.d/vendor/vimpulseohne es zuerst zu löschen ( hier und hier erklärt ) und dann erneut hinzuzufügen.

Braucht Git wirklich den gesamten Pfad im Submodul-Tag?

[submodule ".emacs.d/vimpulse"]

oder ist es auch möglich, nur den Namen des Teilprojekts zu speichern?

[submodule "vimpulse"]
thisch
quelle
HINWEIS: Das OP beantwortet seine eigene Frage mit dem git mvBefehl direkt in der Frage.
Dan Rosenstark
Sie können jedoch nicht so verwenden git mv. Verwenden Sie deinitdann rm wie angegeben stackoverflow.com/a/18892438/8047 .
Dan Rosenstark
14
@Yar: Zumindest auf Git 2.0.0, git mv funktioniert nur für Submodule, keine Notwendigkeit für etwas anderes.
Pedro Romano
9
Beginnend mit Git wird das 1.8.5Verschieben von Submodulen nativ mit dem git mvBefehl unterstützt ( aus den Versionshinweisen, die zuerst von @thisch selbst verlinkt wurden). Auch hier beantwortet
dennisschagt
git mvVerschiebt das Submodul im Arbeitsbereich und aktualisiert die .git-Dateien des Submoduls korrekt, aber der Unterordner im Ordner .git / modules des übergeordneten Repos bleibt gleich - ist das in Ordnung? (Ich benutze Git 2.19.0 unter Windows)
Jojo

Antworten:

377

Hinweis: Wie in den Kommentaren erwähnt, bezieht sich diese Antwort auf die Schritte, die bei älteren Versionen von git erforderlich sind. Git bietet jetzt native Unterstützung für das Verschieben von Submodulen:

Seit Git 1.8.5 git mv old/submod new/submodfunktioniert es wie erwartet und erledigt die gesamte Installation für Sie. Möglicherweise möchten Sie Git 1.9.3 oder höher verwenden, da es Korrekturen für das Verschieben von Submodulen enthält.


Der Vorgang ähnelt dem Entfernen eines Submoduls (siehe Wie entferne ich ein Submodul? ):

  1. Bearbeiten .gitmodulesund ändern Sie den Pfad des Submoduls entsprechend und fügen Sie ihn in den Index mit ein git add .gitmodules.
  2. Erstellen Sie bei Bedarf das übergeordnete Verzeichnis des neuen Speicherorts des Submoduls ( mkdir -p new/parent).
  3. Verschieben Sie den gesamten Inhalt vom alten in das neue Verzeichnis ( mv -vi old/parent/submodule new/parent/submodule).
  4. Stellen Sie sicher, dass Git dieses Verzeichnis verfolgt ( git add new/parent).
  5. Entfernen Sie das alte Verzeichnis mit git rm --cached old/parent/submodule.
  6. Verschieben Sie das Verzeichnis .git/modules/old/parent/submodulemit seinem gesamten Inhalt nach .git/modules/new/parent/submodule.
  7. Bearbeiten Sie die .git/modules/new/parent/configDatei, und stellen Sie sicher, dass das Arbeitsbaumelement auf die neuen Speicherorte verweist. In diesem Beispiel sollte dies der Fall sein worktree = ../../../../../new/parent/module. Normalerweise sollten sich ..an dieser Stelle zwei weitere Verzeichnisse im direkten Pfad befinden.
  8. Bearbeiten Sie die Datei new/parent/module/.git, und stellen Sie sicher, dass der Pfad darin auf den richtigen neuen Speicherort im Hauptprojektordner verweist. .gitIn diesem Beispiel also gitdir: ../../../.git/modules/new/parent/submodule.

    git status Die Ausgabe sieht für mich danach so aus:

    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #       modified:   .gitmodules
    #       renamed:    old/parent/submodule -> new/parent/submodule
    #
    
  9. Übernehmen Sie abschließend die Änderungen.

Axel Beckert
quelle
37
Wenn Sie .gitmodules aktualisieren, stellen Sie sicher, dass Sie sowohl diese pathKonfiguration als auch den Namen des Submoduls aktualisieren . Wenn Sie beispielsweise foo / module nach bar / module verschieben, müssen Sie in .gitmodules den Abschnitt [submodule "foo/module"]in [submodule "bar/module"]und unter demselben Abschnitt path = foo/modulein ändern path = bar/module. Außerdem müssen Sie in .git / config den Abschnitt [submodule "foo/module"]in ändern [submodule "bar/module"].
Wilhelmtell
3
Es hat auch bei mir nicht funktioniert ... Die nächste Lösung, die ich gefunden habe, ist das Löschen eines Submoduls (ein Schmerz) und das erneute Hinzufügen an der anderen Stelle.
Pablo Olmos de Aguilera C.
33
Ein sehr sehr wichtiger Hinweis: Wenn Sie fatal: 'git status --porcelain' failed in...nur .git-Dateien oder -Verzeichnisse im Submodul löschen.
Antitoxikum
19
Es sieht so aus, als ob in diesem Beitrag einige Schritte fehlen, z. B. Bearbeiten .git/modules/old/parent/submodule, Verschieben an den neuen Speicherort, Aktualisieren gitdirin old/parent/submodule/.git...
Szx
38
Seit Git 1.8.5 git mv old/submod new/submodfunktioniert es wie erwartet und erledigt die gesamte Installation für Sie. Sie möchten wahrscheinlich Git 1.9.3+ verwenden, da es Korrekturen für das Verschieben von Submodulen enthält.
Valloric
232

Die modernste Antwort aus Vallorics Kommentar oben:

  1. Upgrade auf Git 1.9.3 (oder 2.18, wenn das Submodul verschachtelte Submodule enthält )
  2. git mv old/submod new/submod
  3. Danach werden die .gitmodules und das Submodule-Verzeichnis bereits für ein Commit bereitgestellt (Sie können dies mit überprüfen git status.)
  4. Übernehmen Sie die Änderungen mit git commitund Sie können loslegen!

Erledigt!

Phatmann
quelle
3
Dies funktionierte tatsächlich mit 1.9.3 Ausnahme eines Submoduls innerhalb des verschobenen Submoduls. Das erforderte eine manuelle Bereinigung.
Pascal
3
Dies sollte bereits in der Version arbeiten , 1.8.5wie beschrieben in der Release Notes .
Dennisschagt
6
Diese Antwort sollte 1000 Upvotes bekommen. Ich habe fast ein Durcheinander mit meinem Repo gemacht, indem ich die oben beschriebenen Schritte ausgeführt habe. StackOverflow sollte wirklich einen Anwendungsfall für diese Situation haben.
MGP
5
Wow, das hat wie ein Zauber funktioniert (Git 1.9.5), ich wünschte, es wäre die ausgewählte Antwort.
Alex Ilyaev
7
Eine Sache, die dies nicht tut, ist, dass es die ursprüngliche Bezeichnung für das Submodul nicht ändert. Wenn Sie die .gitmodulesDatei überprüfen, wird die Datei old/submodweiterhin als Bezeichnung für das Submodul verwendet, während der Pfad geändert wurde. Um auch die Beschriftung zu ändern, müssen Sie anscheinend den Verzeichnispfad des Moduls verschieben .gitund die Beschriftung dann manuell ändern .gitmodules.
CMCDragonkai
55

In meinem Fall wollte ich ein Submodul aus einem Verzeichnis in ein Unterverzeichnis verschieben, z. B. "AFNetworking" -> "ext / AFNetworking". Dies sind die Schritte, die ich befolgt habe:

  1. Bearbeiten Sie .gitmodules, indem Sie den Namen und den Pfad des Submoduls in "ext / AFNetworking" ändern.
  2. Verschieben Sie das Git-Verzeichnis des Submoduls von ".git / modules / AFNetworking" nach ".git / modules / ext / AFNetworking".
  3. Verschieben Sie die Bibliothek von "AFNetworking" nach "ext / AFNetworking".
  4. Bearbeiten Sie ".git / modules / ext / AFNetworking / config" und korrigieren Sie die [core] worktreeZeile. Meins änderte sich von ../../../AFNetworkingzu../../../../ext/AFNetworking
  5. Bearbeiten Sie "ext / AFNetworking / .git" und korrigieren Sie gitdir. Meins änderte sich von ../.git/modules/AFNetworkingzu../../git/modules/ext/AFNetworking
  6. git add .gitmodules
  7. git rm --cached AFNetworking
  8. git submodule add -f <url> ext/AFNetworking

Schließlich sah ich im Git-Status:

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. Das obige Beispiel ändert nicht die Verzeichnistiefe, was einen großen Unterschied zur Komplexität der Aufgabe macht, und ändert auch nicht den Namen des Submoduls (was möglicherweise nicht wirklich notwendig ist, aber ich habe es getan, um mit dem übereinzustimmen würde passieren, wenn ich ein neues Modul an diesem Pfad hinzufügen würde.)

Matt Connolly
quelle
4
Danke Matt. Ich war bei der akzeptierten Antwort verloren. Vielen Dank, dass Sie mehr als den Basisfall behandelt haben. Das hat wie ein Zauber gewirkt.
Andrew Hubbs
Sie müssen nicht durch .git / modules-Pfade mischen oder den Namen des Submoduls ändern (wie arand und Bob Bell erwähnen). Dies kann jedoch dazu führen, dass die Dinge sauberer bleiben.
Gatoatigrado
Vergessen Sie nicht, die Schritte 2, 3, 4 und 5 für alle Sub-Submodule rekursiv auszuführen.
Herzbube
22

[Update: 26.11.2014] Wie Yar unten ausführlich zusammenfasst , stellen Sie sicher, dass Sie die URL des Submoduls kennen , bevor Sie etwas unternehmen. Wenn unbekannt, öffnen .git/.gitmodulesund untersuchen Sie den Schlüssel submodule.<name>.url.

Was für mich funktionierte, war das Entfernen des alten Submoduls mit git submodule deinit <submodule>gefolgt von git rm <submodule-folder>. Fügen Sie dann das Submodul erneut mit dem neuen Ordnernamen hinzu und schreiben Sie fest. Wenn Sie den Git-Status vor dem Festschreiben überprüfen, wird das alte Submodul in den neuen Namen umbenannt und das Git-Modul geändert.

$ 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
quelle
1
Dies erfordert Git 1.8.3 oder höher. Siehe diesen Beitrag für die Aktualisierung Ihres Git: evgeny-goldin.com/blog/3-ways-install-git-linux-ubuntu
Michael Cole
1
Oder besser gesagt: sudo add-apt-repository ppa: git-core / ppa sudo apt-get update sudo apt-get install git
Michael Cole
@ MichaelCole Danke! Du hast Recht! Siehe Git-1.8.3 Versionshinweise . Zu Ihrer Information : Ubuntu-13.10 (Saucy Salamander) hat Git-1.8.3.2 , aber gut zu wissen, dass es ppa gibt . Außerdem ist die IMHO- Strategie zum Zusammenführen von Git-Teilbäumen ein besserer Ansatz. Ich habe Submodule für meine eigenen Projekte aufgegeben. Für bestehende Projekte immer noch gut zu verstehen.
Mark Mikofski
Ich habe verschiedene Lösungen ausprobiert, aber Ihre ist die beste. Verwenden Sie nur die Befehlszeile, damit Sie keine Git-Datei ändern müssen (und sollten). Vielen Dank!
nahung89
12

Der Trick scheint zu verstehen, dass das .gitVerzeichnis für Submodule jetzt im Master-Repository unter gespeichert .git/modulesist und jedes Submodul eine .gitDatei hat, die darauf verweist. Dies ist das Verfahren, das Sie jetzt benötigen:

  • Bewegen Sie das Submodul in sein neues Zuhause.
  • Bearbeiten Sie die .gitDatei im Arbeitsverzeichnis des Submoduls und ändern Sie den darin enthaltenen Pfad so, dass er auf das richtige Verzeichnis im Verzeichnis des Master-Repositorys verweist .git/modules.
  • Geben Sie das .git/modulesVerzeichnis des Master-Repositorys ein und suchen Sie das Verzeichnis, das Ihrem Submodul entspricht.
  • Bearbeiten Sie die configDatei und aktualisieren Sie den worktreePfad so, dass er auf den neuen Speicherort des Arbeitsverzeichnisses des Submoduls verweist.
  • Bearbeiten Sie die .gitmodulesDatei im Stammverzeichnis des Master-Repositorys und aktualisieren Sie den Pfad zum Arbeitsverzeichnis des Submoduls.
  • git add -u
  • git add <parent-of-new-submodule-directory>(Es ist wichtig, dass Sie das übergeordnete Verzeichnis und nicht das Submodulverzeichnis selbst hinzufügen .)

Ein paar Anmerkungen:

  • Die [submodule "submodule-name"]Zeilen in .gitmodulesund .git/configmüssen übereinstimmen, müssen aber nichts anderem entsprechen.
  • Das Submodul-Arbeitsverzeichnis und das .gitVerzeichnis müssen korrekt aufeinander verweisen.
  • Das .gitmodulesund.git/config Dateien sollten synchronisiert werden.
Paul Gideon Dann
quelle
9

Die Zeichenfolge in Anführungszeichen nach "[Submodul" spielt keine Rolle. Sie können es in "foobar" ändern, wenn Sie möchten. Es wird verwendet, um den passenden Eintrag in ".git / config" zu finden.

Wenn Sie die Änderung vornehmen, bevor Sie "git submodule init" ausführen, funktioniert dies daher einwandfrei. Wenn Sie die Änderung vornehmen (oder die Änderung durch Zusammenführen übernehmen), müssen Sie entweder .git / config manuell bearbeiten oder "git submodule init" erneut ausführen. Wenn Sie Letzteres tun, bleibt ein harmloser "gestrandeter" Eintrag mit dem alten Namen in .git / config übrig.

Bob Bell
quelle
Das ist wirklich nervig, aber du hast recht. Das Schlimmste ist, wenn Sie nur die URL ändern und git init nicht zu aktualisieren scheint, müssen Sie .git / config manuell bearbeiten.
Crimson_penguin
1
In diesem Fall wird git submodule syncdie Änderung .git/configautomatisch an
CharlesB
9

Sie können einfach ein neues Submodul hinzufügen und das alte Submodul mit Standardbefehlen entfernen. (sollte versehentliche Fehler in .git verhindern)

Beispieleinrichtung:

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>

Beispiel: Verschieben Sie 'jquery' nach '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}"

Bonusmethode für große Submodule:

Wenn das Submodul groß ist und Sie nicht auf den Klon warten möchten, können Sie das neue Submodul mit dem alten als Ursprung erstellen und dann den Ursprung wechseln.

Beispiel (verwenden Sie das gleiche Beispielsetup)

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
quelle
Wenn Sie head nicht verwenden, müssen Sie möglicherweise auch die richtige Version des Moduls unter überprüfen newPath.
Paulmelnikow
2

Die angegebene Lösung hat bei mir nicht funktioniert, eine ähnliche Version jedoch ...

Dies ist bei einem geklonten Repository der Fall, daher sind die Git-Repos des Submoduls in den Top-Repositorys .git dir enthalten. Alle Kationen stammen aus dem obersten Repository:

  1. Bearbeiten Sie .gitmodules und ändern Sie die Einstellung "path =" für das betreffende Submodul. (Sie müssen weder die Bezeichnung ändern noch diese Datei zum Index hinzufügen.)

  2. Bearbeiten Sie .git / modules / name / config und ändern Sie die Einstellung "worktree =" für das betreffende Submodul

  3. Lauf:

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

Ich frage mich, ob es einen Unterschied macht, ob die Repositorys atomare oder relative Submodule sind, in meinem Fall war es relativ (Submodul / .git ist ein Verweis zurück auf topproject / .git / modules / submodule).

arand
quelle
2

Verwenden Sie einfach das Shell-Skript git-submodule-move .

Flimm
quelle
Heh, ich habe diese Frage noch einmal nachgeschlagen und eine der höher bewerteten Antworten verwendet, und jetzt wünschte ich, ich hätte nach unten gescrollt und meine vorherige Antwort gesehen, die ich vergessen hatte.
Flimm
2

Ich habe gestern gerade diese Tortur durchgemacht und diese Antwort hat perfekt funktioniert. Hier sind meine Schritte zur Klarheit:

  1. Stellen Sie sicher, dass das Submodul eingecheckt und auf seinen Server übertragen wird. Sie müssen auch wissen, auf welchem ​​Zweig es ist.
  2. Sie benötigen die URL Ihres Submoduls! Verwenden more .gitmodulesSie diese Option, da das Submodul nach dem Löschen nicht mehr vorhanden sein wird
  3. Jetzt können Sie verwenden deinit, rmund dannsubmodule add

BEISPIEL

BEFEHLE

    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 

HINWEIS: git mv macht das nicht. Überhaupt.

Dan Rosenstark
quelle
3
Gute Zusammenfassung. +1 git mvsollte in den allerletzten Versionen von Git besser sein.
VonC
@VonC Ich habe auf Git 1.8.5 getestet, ziemlich sicher, dass das ungefähr so ​​gut ist, wie es nur geht mv. Vielen Dank!
Dan Rosenstark