Git Handarbeit II: Submodules

written by Martin Häcker on

Noch so eine Stelle an der GIT einem extra viel Handarbeit aufdrückt. Submodules.

Erst mal die Idee (die eigentlich ganz gut ist): Oft will man Teile der Software (Frameworks, Plugins, ...) eigentlich als eigenes Projekt in einem eigenen Repository entwickeln. Und das ist GUT (TM).

Daher bieten eigentlich alle etwas fortgeschritteneren Versionskontrollsysteme irgend eine Möglichkeit solche externen Repositories einzubinden, damit man es einfach hat an aktuelle Versionen dieses Codes heranzukommen.

Dazu gibt es jetzt in der Regel zwei Ansätze: Entweder man verlinkt einfach auf den HEAD des anderen Repos oder auf eine bestimmte Revision. Letzteres ist im allgemeinen Fall zwingend, denn sonst hat man nie die Chance einen alten Build auch tatsächlich exakt wieder herzustellen - im Speziellen Fall ist ersteres aber sehr Praktisch, wenn man z.B. aus einem globalen Repository einfach Teile an verschiedenen Stellen einblenden möchte, damit sie im Repo nur einmal, im Checkout aber mehrfach oder einfach an einer anderen Stelle erscheinen.

SVN macht das mit svn:external attributen die sowohl auf HEAD als auch auf spezifische Revisionen verlinken können. HG macht das mit forests (noch eine extension), bzr weiß ich nicht und git macht das mit submodules.

Bei SVN hat man noch den Nachteil das es, weil es branches und tags nur als Verzeichnisse kennt natürlich auch Handarbeit erfordert, das hießt, dass man beim Taggen von HEAD z.B. nicht automatisch von dem link auf einen anderen HEAD auf einen Link auf eine spezifische Revision umschalten kann. Das gibt dann das Ergebnis, dass man oft im Tag auf den HEAD eines anderen Teils des Repos verweist. Gratulation! Und wiedererzeugbare Builds ade.

Besonders geärgert haben mich aber die GIT-Submodules. Zuerst: Die sind auch ein Plugin - und in bester GIT manier gibt es natürlich überhaupt keine integration in die anderen Kommandos.

Das bedeutet schon mal das man nicht ein Repository pullen kann um danach einen Build zu machen - NEIN, man muss erst merken dass man noch die Submodules benötigt und dann git submodule init && git submodule update eingeben.

Yeah. Give me useless extra steps!

Es wird aber noch besser, weil es keine Intgegration gibt, sieht man natürlich mit git status nicht das es in einem submodule Änderungen gab. Ok, das stimmt nicht ganz. Man sieht nicht dass es in einem submodule uncommittete Änderungen gab. Commitet man dann nämlich dort, dann sieht man im parent repository dass sich etwas verändert hat - und dass muss man dann nochmal committen.

Yeah. Give me useless extra steps!

Auch schön, wenn man z.B. von GitHub ein Projekt mit Submodules auscheckt, dann zeigt der Origin des Projekts auf GitHub - sinnvoll, weil dahin wird man seine eigenen changes ja schieben wollen, damit Upstream sie mergen kann. Nicht so bei submodules - dort zeigt der origin natürlich auf das ursprüngliche Projekt - auf das man natürlich regelmäßig nicht pushen kann/will. Man muss also einen eigenen branch des submodules auf GitHub anlegen und dann das bei sich von hand als Branch registrieren und dann immer daran denken das im submodule natürlich nicht origin sonder ein anderer name für den parent branch gilt.

Yeah. Give me useless extra steps!

Hach, und natürlich sind GIT submodules IMMER auf eine bestimmte Revision gebunden - tollerweise auch gleich ohne mitzubekommen auf welchem Branch diese jetzt liegt. Das heißt dass man sowieso dort drin per default nix committen kann. Man muss also in jedem fall einen eigenen Remote clone des origins anlegen, den als neuen Remote eintragen, dann einen lokalen tracking branch erstellen, auf den wechseln, dort dann commiten und jeweils nicht vergessen diese Commits im Parent Repo dann zu bestätigen (einzeln natürlich, sonst sieht man dort die history nicht). Das geile daran: macht man dann im Parent Repo einmal git submodule update ist man natürlich wieder auf einer disconnected revision.

Yeeehaw. Give me useless extra steps!

Umbenennen ist noch so eine Sache, DVCS sind ja so toll beim Mergen, nicht? Aber wehe man benennt ein Submodule um. Dann nämlich kriegt man das nach git pull && git submodule update NICHT. Nein, viel besser man muss lediglich .git/config von hand bearbeiten um den alten submodule Eintrag zu entfernen und dann ein git submodule init && git submodule update machen.

Yeah. Give me useless extra steps!

Mein Fazit: GIT, das Tool für Leute die gerne mehr Zeit in ihr DVCS als in ihre Software stecken wollen.