27. August 2013

Verwendung von Unterkomponenten: git submodule

Mit einem Submodule wird in einem Unterverzeichnis eines Git-Repositories eine Referenz auf ein anderes Git-Repositories eingebettet. Zum Beispiel könnte ein Projekt eine verwendete Bibliothek als Submodul einbinden. Dabei wird mit den Commits des Projektrepositories festgeschrieben, welcher Stand des eingebetteten Submodul-Repositories verwendet werden soll:

Submodule anlegen

Submodule hinzufügen:

$ git submodule add <repository> <path>
$ git submodule add git://github.com/jquery/jquery.git libs/jquery/

Dadurch wird das Submodul mit Pfad und Repository-URL in die Projektdatei .gitmodules eingetragen:

[submodule "libs/jquery"]
path = libs/jquery/
url = git://github.com/jquery/jquery.git

Diese Änderung muss committed werden:

$ git status -s
A  .gitmodules
A  libs/jquery
$ git commit "added submodule"

Neben der Konfiguration in .gitmodules wird nun unter dem Submodul-Pfad eine Referenz auf den Commit des eingebetteten Repositories versioniert:

$ git ls-tree master -r
100644 blob 02a7aca40d2bf613c9c79e6c0bfaf2c2c6eecca9    .gitignore
100644 blob 29c99edd93da171b53fbb1f91cb5c730361552fd    .gitmodules
100644 blob 9ddb02df2fa3245829f3b644933ef70c28afb2d8    css/style.css
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391    html/index.html
160000 commit 2ac1cd91db5c20cbe8ba0db44f7640cd150060ee    libs/jquery      <<<<<<<<

Befindet man sich im Verzeichnis des Submoduls, beziehen sich alle Git-Kommandos auf das Submodul. Ändert sich hier nun die HEAD-Referenz, zum Beispiel durch einen Commit oder einen Branch-Wechsel, bewirkt dies eine Änderung in dem äußeren Repository:

$ cd ~/example/libs/jquery/
$ git checkout 2.0.2

$ cd ~/example/

$ git status -s
 M libs/jquery

$ git diff
[...]
-Subproject commit 2ac1cd91db5c20cbe8ba0db44f7640cd150060ee
+Subproject commit b21c88ff0c293db0711d378411901259052ca2b4

$ git add libs/jquery
$ git commit

Dabei gilt es zu beachten, dass Git den Stand im Submodul nicht verändert, ohne dass dies explizit angegeben wird. Wechselt man zum Beispiel im äußeren Repository in einen Branch, der eine andere Version des Submodules referenziert, bleibt das Submodul-Repository zunächst unverändert. Dies ist sichtbar mit git submodule status:

$ git submodule status
-fbb52573d4dcb09d02e7a8c1fd586076dc0d1685 module1    # nicht initialisiert
+9ddb02df2fa3245829f3b644933ef70c28afb2d8 module2    # nicht aktuell
 b1633b39058b6b6b4c0a556448d8536b4e5f6022 module3    # aktuell

Mit git submodule update wird das Repository in den entsprechenden Zustand gebracht:

$ git submodule update
Submodule path 'module1': checked out 'fbb52573d4dcb09d02e7a8c1fd586076dc0d1685'

Repository mit Submodulen klonen

Klont man ein Repository mit Submodulen, werden diese von Git zunächst ignoriert und müssen explizit initialisiert werden:

$ git submodule update --init
Submodule 'libs/jquery' (git://github.com/jquery/jquery.git) registered for path 'libs/jquery'
Cloning into 'libs/jquery'... [...]
Submodule path 'libs/jquery': checked out 'b21c88ff0c293db0711d378411901259052ca2b4'

Alternativ können die Submodule direkt beim Klonen eingerichtet werden:

$ git clone --recursive [url]

Aufgaben

  1. Legen Sie ein neuen Ordner parentrepo an und erstellen Sie hier ein neues Git-Repository.
  2. Fügen Sie diesem das GitHub-Repository als Sub-Modul hinzu, so dass Sie Inhalte des Repositories auch in Ihrem Repository sehen.
  3. Committen Sie eine Änderung in dem Submodul-Repository und übernehmen Sie den neuen Stand in dem Parent-Repository.