Alternative zu Git Submodulen: GWS (Git Workspace)

Ein Git Repository zu pflegen ist keine Hexerei. Ein Git Repository mit Referenzen zu anderen Repositories kann jedoch sehr schnell komplex werden. Git bringt dafür einige Hilfsmittel mit, z.B. Git Submodule oder Git Subtree. Beide Techniken sind relativ komplex und bringen ihre Vor- und vorallem Nachteile mit.

Wir pflegen unsere Puppet Hiera Daten in YAML Dateien, welche in Git Repositories versionisiert werden. Hiera besteht in seiner einfachsten Anwendung aus einem einzelnen Verzeichnisbaum, welcher die Hierarchie abbildet. Unsere Anforderung ist, dass diese Hierarchiestufen in unterschiedlichen Git Repositories liegen.

Hierfür verwendeten wir zu Beginn Git Submodule, sind dabei aber auf einige Probleme gestossen. Das grösste Problem ist, dass ein Git Submodule immer auf einen bestimmen Git Commit referenziert. Möchte man immer auf den aktuellsten Commit referenzieren, muss man jedesmal die Referenz im Hauptrepository anpassen. Dies ist nicht praktikabel für unseren Anwendungsfall, da wir immer die aktuellsten Commits verwenden möchten.

Wechselt man in ein Unterverzeichnis, welches ein Git Submodule ist, hat man die Möglichkeit, mit den bekannten Git Befehlen zu arbeiten. So wäre es möglich, in diesem Unterverzeichnis mit einem git checkout master den Master Branch auf dem aktuellsten Commit auszuchecken. Dies passt jedoch die Referenz im Hauptrepository nicht an. Klont nun jemand das Hauptrepository vom Git Server, erhält er immer den Verweis auf den Commit im Submodul, welcher referenziert ist.

Auf der Suche nach einer Lösung, Referenzen zu mehreren Repositories in einem Hauptrepository pflegen zu können, sind wir auf ein Tool namens GWS – Git Workspace gestossen.

Was ist GWS (Git Workspace)?

gws is a KISS, bash, colorful helper to manage workspaces composed of git repositories.

Wie die Einführung des Autors von GWS bereits erklärt, handelt es sich bei GWS um ein einfaches Bash Skript, welches Referenzen zu Git Repositories in einer einfachen Textdatei speichert und einige Hilfsmittel anbietet, um mit diesen Referenzen zu arbeiten. Das Interessante daran ist, dass das Bash Skript ohne Abhängigkeiten (ausser Git und Bash) auskommt und auch direkt, zusammen mit der Textdatei, mit den Referenzen gespeichert werden kann.

Wie arbeite ich mit GWS?

Als erstes lädt man sich das Bash Skript vom GitHub Projekt herunter: StreakyCobra/gws. Anschliessend wird eine Textdatei mit dem Namen .projects.gws angelegt, welche die Referenzen zu den gewünschten Repositories beinhaltet:

# Puppet modules
stdlib    | https://github.com/puppetlabs/puppetlabs-stdlib.git
apache    | https://github.com/puppetlabs/puppetlabs-apache.git
apt       | https://github.com/puppetlabs/puppetlabs-apt.git

Hinweis: Zeilen, welche mit # beginnen gelten als Kommentare.

Als nächstes initialisiert man die Repositories mit gws update:

Nun wurden alle referenzierten Git Repositories in die angegebenen Unterverzeichnisse geklont. Diese Unterverzeichnisse sind unabhängige Git Repositories und man kann mit diesen arbeiten wie mit ganz normalen Git Repositories.

Tipp: Das Verzeichnis, welches die Datei .projects.gws (und ggf. das GWS Skript selber) beinhaltet, kann auch in einem Git Repository gepflegt werden. Man sollte jedoch darauf achten, eine saubere .gitignore Datei zu erstellen. Beispiel:

# Ignore everything, so all repositories in our case
*
# But not these files
!.projects.gws
!.gitignore
!gws
!README.md

Weitere Tricks mit GWS

Der oben beschriebene Einstieg in GWS ist erst der Anfang. Das Tool bietet noch einige weitere coole Features.

Schnelles Initialisieren

Hat man bereits viele verschiedene Git Repositories in einem Verzeichnis, hilft gws init, ein Inventar aller Git Repositories in den Unterverzeichnissen zu erstellen und diese in der Datei .projects.gws zu erfassen.

 

Status

Mittels gws status sieht man auf den ersten Blick, ob alle Repositories auf dem neuesten Stand sind, ob Änderungen nicht committed wurden, etc.

 

Update aller Repositories

Möchte man z.B. alle referenzierten Repositories auf den neuesten Stand bringen, kann man dies einfach mit gws ff machen. Dies macht in allen Repositories einen git pull. Oder mit gws fetch wird in allen Repositories ein git fetch durchgeführt.