git submodule init: Submodule richtig initialisieren

Programmierung

Sie klonen ein Repository, das externe Bibliotheken als Submodule einbindet – doch die entsprechenden Ordner sind leer. Der Grund: Git lädt Submodule beim Klonen standardmäßig nicht mit herunter. git submodule init ist der erste von zwei Schritten, um das zu ändern. Nach diesem Text wissen Sie genau, was der Befehl tut, wo der Unterschied zu git submodule update liegt und wie Sie die häufigsten Stolperfallen vermeiden.

Was git submodule init genau macht

Ein Submodul ist ein Git-Repository innerhalb eines anderen Repositorys (dem sogenannten Superprojekt). Welche Submodule ein Projekt hat, steht in der versionierten Datei .gitmodules im Wurzelverzeichnis. Ein Eintrag sieht so aus:

[submodule "libs/vendor"]
	path = libs/vendor
	url = https://github.com/beispiel/vendor.git

git submodule init liest diese Einträge und kopiert sie in Ihre lokale Konfiguration .git/config. Erst dadurch ist das Submodul auf Ihrem Rechner „registriert”. Wichtig: Der Befehl lädt keinerlei Code herunter. Er trägt lediglich Namen und URL des Submoduls in .git/config ein – zum Beispiel als Schlüssel submodule.libs/vendor.url.

Dieser Zwischenschritt ist Absicht. Weil die URL nun in Ihrer lokalen Config steht, können Sie sie vor dem eigentlichen Download noch anpassen – etwa auf einen internen Mirror oder eine SSH-Adresse. Das ist der eigentliche Sinn der Trennung von „init” und „update”.

Der komplette Ablauf: init und update

Das Einbinden eines Submoduls besteht immer aus zwei Phasen: registrieren (init) und herunterladen (update).

Bei einem bereits geklonten Repository

Sie haben ein Repo geklont und stellen fest, dass die Submodul-Ordner leer sind:

git submodule init
git submodule update

git submodule update liest die in Phase 1 hinterlegte URL aus .git/config, klont das Submodul in den vorgesehenen Pfad und checkt exakt den Commit aus, den das Superprojekt gespeichert hat. Deshalb landet das Submodul anschließend in einem sogenannten detached HEAD – es zeigt auf einen festen Commit, nicht auf einen Branch. Das ist normal und beabsichtigt: So bleibt reproduzierbar, welcher Stand der Abhängigkeit zu Ihrem Projektstand gehört.

Beide Schritte lassen sich zusammenfassen:

git submodule update --init

Bei verschachtelten Submodulen (Submodule, die selbst Submodule enthalten) ergänzen Sie --recursive:

git submodule update --init --recursive

Beim Klonen alles in einem Schritt

Am bequemsten ist es, Submodule direkt beim Klonen mitzunehmen. Dann entfällt init als separater Aufruf:

git clone --recurse-submodules https://github.com/beispiel/projekt.git

Die Option --recurse-submodules steht in allen aktuellen Git-Versionen zur Verfügung; die Kurzform --recursive funktioniert weiterhin als Alias. Verwandtes zum Klonen und Aktualisieren finden Sie unter Was macht git fetch genau? und Ist git fetch und merge dasselbe wie pull?.

Nur bestimmte Submodule initialisieren

Sie müssen nicht alle Submodule aktivieren. Übergeben Sie einen Pfad, um gezielt einzelne zu registrieren:

git submodule init libs/vendor
git submodule update libs/vendor

Das ist praktisch bei großen Monorepos, in denen Sie nur einen Teil der Abhängigkeiten benötigen.

Wie sich .gitmodules und .git/config unterscheiden

Diese beiden Dateien werden oft verwechselt, obwohl der Unterschied zentral ist:

  • .gitmodules liegt im Projekt und wird versioniert. Sie ist für alle Beteiligten identisch und definiert, welche Submodule existieren.
  • .git/config ist rein lokal und wird nie eingecheckt. Erst git submodule init schreibt die Submodul-URLs dorthin.

Daraus folgt eine typische Falle: Ändert jemand die URL in .gitmodules (etwa bei einem Umzug von GitHub zu GitLab), übernimmt git submodule init diese Änderung nicht, wenn der Eintrag in Ihrer .git/config bereits existiert. Dafür gibt es einen eigenen Befehl:

git submodule sync

git submodule sync überträgt die aktuelle URL aus .gitmodules in Ihre lokale Config. Danach greift git submodule update wieder auf die richtige Quelle zu.

Nützliche Befehle rund um Submodule

  • git submodule status – zeigt Commit-Hash und Zustand jedes Submoduls. Ein - am Zeilenanfang bedeutet „nicht initialisiert”, ein + „ausgecheckter Commit weicht vom gespeicherten ab”. Siehe auch Wie überprüfe ich den aktuellen Git-Status?.
  • git submodule update --remote – holt den neuesten Commit des in .gitmodules hinterlegten Branches, statt am fest gespeicherten Commit zu bleiben.
  • git submodule deinit <pfad> – macht init rückgängig: entfernt den Eintrag aus .git/config und leert das Arbeitsverzeichnis des Submoduls. Mit --all für alle Submodule.
  • git config submodule.recurse true – sorgt dafür, dass Befehle wie git pull und git checkout automatisch in Submodule hineinlaufen. Das erspart viele vergessene Updates.

Typische Fehler und ihre Lösung

„Submodule … not initialized. Maybe you want to use ‘update —init’?” Sie haben git submodule update ohne vorheriges init ausgeführt. Lösung: git submodule update --init verwenden.

Submodul-Ordner bleibt nach dem Klonen leer. --recurse-submodules wurde beim Klonen vergessen. Holen Sie es nach mit git submodule update --init --recursive.

URL-Änderung in .gitmodules wird ignoriert. Ihre lokale .git/config enthält noch die alte URL. Führen Sie git submodule sync aus und danach erneut git submodule update.

Nach einem git pull zeigt das Submodul auf den alten Stand. Das Superprojekt speichert nur einen Zeiger auf einen Commit; ein pull im Hauptprojekt aktualisiert das Submodul nicht automatisch. Führen Sie anschließend git submodule update aus – oder aktivieren Sie submodule.recurse (siehe oben).

FAQ

Muss ich git submodule init bei jedem Klonen ausführen? Nein. Wenn Sie mit git clone --recurse-submodules klonen, erledigt Git init und update automatisch. Der separate Aufruf ist nur nötig, wenn Sie ein bereits geklontes Repo nachträglich um Submodule ergänzen oder gezielt einzelne aktivieren wollen.

Was ist der Unterschied zwischen git submodule init und git submodule update? init registriert die Submodule lokal, indem es die URLs aus .gitmodules in .git/config kopiert – ohne Download. update klont dann den Code und checkt den vom Superprojekt gespeicherten Commit aus. Ohne init weiß update nicht, woher es das Submodul beziehen soll.

Warum befindet sich mein Submodul in einem „detached HEAD”? Weil das Superprojekt einen exakten Commit referenziert, nicht einen Branch. git submodule update checkt genau diesen Commit aus. Wollen Sie im Submodul weiterarbeiten, wechseln Sie mit git checkout <branch> auf einen Branch. Mehr dazu unter Wie checke ich einen Commit in Git aus?.