Submodule: Kernkonzept, Workflows und Tipps
Nicola Paolucci
Developer Advocate
Durch die Arbeit mit Untermodulen in deiner Git-Entwicklung kannst du andere Projekte in deine Codebasis einschließen. Dabei werden deren Verläufe separat gehalten, aber gleichzeitig mit deinem synchronisiert. Dies ist eine praktische Methode zum Lösen der Probleme durch Fremdbibliotheken und Abhängigkeiten. Wie bei allem rund um Git
ist die Vorgehensweise eigenwillig und erfordert ein wenig Lernaufwand, bevor sie kompetent angewendet werden kann. Es gibt bereits gute und detaillierte Informationen zu den Untermodulen
, diese werde ich hier nicht wiederholen. Stattdessen werde ich ein paar interessante Punkte erläutern, mit denen du das Optimum aus dem Feature herausholen kannst.
Inhaltsverzeichnis
Zugehöriges Material
Verschieben eines vollständigen Git-Repositorys
Lösung anzeigen
Git kennenlernen mit Bitbucket Cloud
Kernkonzept
Zuerst möchte ich kurz ein Kernkonzept der Untermodule erklären, dessen Verständnis die Arbeit mit ihnen erleichtern wird.
Untermodule werden nach dem genauen Commit verfolgt, der im übergeordneten Projekt angegeben ist, nicht nach einem Branch, einer Referenz oder einer anderen symbolischen Referenz.
Sie werden niemals automatisch aktualisiert, wenn das vom Untermodul angegebene Repository aktualisiert wird – nur wenn das übergeordnete Projekt aktualisiert wird. Wie im bereits erwähnten Kapitel Pro Git sehr deutlich zum Ausdruck gebracht:
Wenn du Änderungen vornimmst und einen Commit in dieses [submodule]-Unterverzeichnis durchführst, bemerkt das Superprojekt, dass sich der HEAD dort geändert hat, und zeichnet den genauen Commit auf, an dem du gerade arbeitest. Auf diese Weise können andere beim Klonen dieses Projekts die Umgebung genau nachbilden.
Oder anders ausgedrückt:
[...] Git-Untermodule [...] sind statisch. Sehr statisch. Mit Git-Untermodulen kannst du bestimmte Commits nachverfolgen – keine Branches, keine Referenzen, sondern einzelne Commits. Wenn du Commits zu einem Untermodul hinzufügst, ist das für das Superprojekt nicht nachvollziehbar. Wenn ein Modul oft geforkt wurde, wird das in den Git-Untermodulen nicht berücksichtigt. Es gibt ein Remote-Repository und der Verweis bezieht sich auf einen einzigen Commit. Alles bleibt unverändert, solange du das Superprojekt nicht aktualisierst.
Mögliche Workflows
Vor dem Hintergrund dieses Kernkonzepts wirst du verstehen, dass submodule
einige Workflows gut und andere weniger optimal unterstützen. Es gibt mindestens drei Szenarien, in denen Untermodule eine gute Wahl sind:
-
Wenn eine Komponente oder ein Unterprojekt sich zu schnell ändert oder bevorstehende Änderungen nicht mit der API kompatibel sind, kannst du zur eigenen Sicherheit den Code in einen bestimmten Commit sperren.
-
Wenn eine Komponente nicht sehr oft aktualisiert wird und du sie als Anbieterabhängigkeit verfolgen möchtest. Ich mache das zum Beispiel bei meinen Vim-Plugins.
-
Wenn du einen Teil des Projekts an eine Drittpartei delegierst und deren Arbeitsergebnisse zu einem bestimmten Zeitpunkt oder beim Release integrieren möchtest. Dies funktioniert bei nicht zu häufigen Updates.
Danke an Finch für die gut erklärten Szenarien.
Einige nützliche Tipps
Mit der leistungsstarken Infrastruktur von Untermodulen kannst du nützliche Aufteilungen und Integrationen von Codebasen durchführen. Allerdings gibt es auch einfache Vorgänge ohne optimierte Verfahren oder umfangreichen Support der Befehlszeilenoberfläche.
Wenn du Git-Untermodule in deinem Projekt verwendest, bist du entweder bereits darauf gestoßen oder wirst es bald. Wenn dies geschieht, musst du die Lösung hierfür nachlesen. Immer wieder. Um dir Recherchezeit zu sparen: Instapaper, Evernote oder Old School setzen ein Lesezeichen für diese Seite (:D:D) und du bist für eine Weile versorgt.
Also, los geht's:
Wie ersetze ich ein Git-Untermodul mit meiner eigenen Fork?
Dies ist ein sehr häufiger Workflow: Du nutzt das Projekt von jemand anderem als Untermodul, aber nach einer Weile stellst du fest, dass du es anpassen musst, deshalb möchtest du das Projekt forken und das Untermodul durch deine eigene Fork ersetzen. Wie geht das?
Die Untermodule werden in .gitmodules
gespeichert:
$ cat .gitmodules [submodule "ext/google-maps"] path = ext/google-maps url = git://git.naquadah.org/google-maps.git
Du kannst die URL einfach mit einem Texteditor bearbeiten und dann Folgendes ausführen:
$ git submodule sync
Dadurch wird .git/config
aktualisiert, welches eine Kopie dieser Untermodul-Liste enthält. (Du könntest auch einfach den entsprechenden Abschnitt [submodule]
von .git/config
manuell bearbeiten.)
Wie entferne ich ein Untermodul?
Dies ist relativ häufig notwendig, die Prozedur ist jedoch etwas kompliziert. So entfernst du ein Untermodul:
1. Lösche die entsprechende Zeile aus der .gitmodules
-Datei.
2. Lösche den entsprechenden Abschnitt aus .git/config
.
3. Führe git rm --cached path_to_submodule
aus (kein Schrägstrich am Ende).
4. Committe und lösche die nun unverfolgten Untermoduldateien.
Wie integriere ich ein Untermodul zurück in mein Projekt?
Oder mit anderen Worten: Wie hört ein Git-Untermodul auf, Untermodul zu sein? Wenn du lediglich den Code aus deinem Untermodul in das Haupt-Repository integrieren möchtest, musst du nur das Untermodul entfernen und die Dateien wieder dem Haupt-Repository hinzufügen:
1. Lösche die Referenz zu dem Untermodul aus dem Index, behalte aber die Dateien:
git rm --cached submodule_path (no trailing slash)
2. Lösche die Datei .gitmodules oder, wenn du mehr als ein Untermodul hast, bearbeite diese Datei und entferne das Untermodul aus der Liste:
git rm .gitmodules
3. Entferne den .git-Metadatenordner (und vergewissere dich, dass du ein Backup davon erstellt hast):
rm -rf submodule_path/.git
4. Füge das submodule
zum Index des Haupt-Repositorys hinzu:
git add submodule_path git commit -m "remove submodule"
HINWEIS: Die obige Vorgehensweise führt zum Löschen des Untermodul-Verlaufs. Falls du also einen übereinstimmenden Verlauf deiner Untermodule beibehalten willst, musst du einen "Merge" durchführen. Wenn du mehr erfahren willst, verweise ich dich auf die sehr umfangreichen Informationen auf Stack Overflow.
Wie ignoriere ich Änderungen in Untermodulen?
Manchmal können deine submodules
von selbst dirty
werden. Wenn du beispielsweise git submodules
verwendest, um deine Vim-Plugins zu verfolgen, können diese lokale Dateien wie helptags
generieren oder ändern. Leider wird dich git status wegen dieser Änderungen nerven, auch wenn du überhaupt nicht an ihnen interessiert bist und sie auch gar nicht committen möchtest.
Die Lösung ist sehr einfach. Öffne die Datei .gitmodules
im Stammverzeichnis deines Repositorys und füge für jedes Untermodul ignore = dirty
hinzu, wie in diesem Beispiel:
[submodule ".vim/bundle/msanders-snipmate"] path = .vim/bundle/msanders-snipmate url = git://github.com/msanders/snipmate.vim.git ignore = dirty
Danke an Nils für die tolle Erklärung.
Achtung! Fallstricke bei der Interaktion mit Remote-Repositorys
Wie wir auch im Git-Tutorial zu Untermodulen auf kernel.org erfahren, gilt es bei der Interaktion mit deinen Remote-Repositorys ein paar Dinge zu beachten.
Zunächst solltest du darauf achten, die Änderung am Untermodul immer vor den Änderungen am darauf verweisenden Superprojekt zu veröffentlichen. Das ist äußerst wichtig, denn ansonsten werden andere Entwicklern womöglich daran gehindert, das Repository zu klonen.
Außerdem solltest du immer alle deine Änderungen committen, bevor du git submodule update
ausführst, denn andernfalls werden diese Änderungen überschrieben.
Fazit
Anhand dieser Erläuterungen solltest du nun in der Lage sein, viele der häufig genutzten, wiederkehrenden Workflows bei Untermodulen bewältigen zu können. In künftigen Blogposts werde ich Alternativen zu git submodule
vorstellen.
Folge mir @durdn und dem großartigen Bitbucket-Team, wenn du mehr über DVCS erfahren willst.
Diesen Artikel teilen
Nächstes Thema
Lesenswert
Füge diese Ressourcen deinen Lesezeichen hinzu, um mehr über DevOps-Teams und fortlaufende Updates zu DevOps bei Atlassian zu erfahren.