Close

Git und Projektabhängigkeiten

Porträtfoto von Nicola Paolucci
Nicola Paolucci

Developer Advocate

Vielleicht stellst auch du dir die folgenden Fragen: Wie geht man in Git mit Projektabhängigkeiten um? Unser Projekt besteht aus mehreren untereinander abhängigen Repositorys. Derzeit verwalten wir sie mit svn:externals. Wie gehen wir mit ihnen in Git am besten um? Wie unterteilt man ein sehr großes Repository mit Git in kleinere Komponenten? Diese Fragen gehören zu den am häufigsten gestellten Fragen bei der europäischen Etappe unserer Getting Git Right-Tour.

Dieses Thema bereitet vielen Softwareteams bei der Einführung von Git Kopfzerbrechen. Dieser Artikel soll Licht ins Dunkel bringen.

Projekt-Abhängigkeiten und Build-Infrastruktur greifen offenbar ineinander, was auch intern bei Atlassian eine Diskussion über die "Zukunft von Builds" entfacht hat.

Separate Repositorys statt einem einzigen können so manches erschweren. Trotzdem ist dies aus mindestens zwei wichtigen Gründen ein relativ natürlicher und manchmal auch zwingend notwendiger Schritt während der Weiterentwicklung eines Softwareprojekts: steigende Build-Zeiten und gemeinsame Abhängigkeiten zwischen Projekten.

Vielleicht stellst auch du dir die folgenden Fragen: Wie geht man in Git mit Projektabhängigkeiten um? Unser Projekt besteht aus mehreren untereinander abhängigen Repositorys. Derzeit verwalten wir sie mit svn:externals. Wie gehen wir mit ihnen in Git am besten um? Wie unterteilt man ein sehr großes Repository mit Git in kleinere Komponenten? Diese Fragen gehören zu den am häufigsten gestellten Fragen bei der europäischen Etappe unserer Getting Git Right-Tour.

Dieses Thema bereitet vielen Softwareteams bei der Einführung von Git Kopfzerbrechen. Dieser Artikel soll Licht ins Dunkel bringen.

Projekt-Abhängigkeiten und Build-Infrastruktur greifen offenbar ineinander, was auch intern bei Atlassian eine Diskussion über die "Zukunft von Builds" entfacht hat.

Separate Repositorys statt einem einzigen können so manches erschweren. Trotzdem ist dies aus mindestens zwei wichtigen Gründen ein relativ natürlicher und manchmal auch zwingend notwendiger Schritt während der Weiterentwicklung eines Softwareprojekts: steigende Build-Zeiten und gemeinsame Abhängigkeiten zwischen Projekten.


Ein Überblick in groben Zügen: Richtlinien und suboptimale Lösungen


Zurück zur Frage: Wie kannst du Projektabhängigkeiten mit Git verfolgen und verwalten?

Am besten gar nicht!

Spaß beiseite. Ich werde diese Frage zuerst mal allgemein beantworten und später ins Detail gehen. Allerdings gibt es für all die Schwierigkeiten mit Projektabhängigkeiten keine Patentlösung, weder in Git noch auf andere Weise.

Sobald ein Projekt eine gewisse Größe erreicht hat, ist es sinnvoll, es logisch zu unterteilen. Warte aber nicht, bis du in einem Repository schon Millionen von Zeilen an Code verfasst hast. Die folgenden Hinweise sollen dir lediglich helfen, deinen eigenen Ansatz zu finden.

Git-Logo
Zugehöriges Material

Git installieren

Bitbucket-Logo
Lösung anzeigen

Git kennenlernen mit Bitbucket Cloud

Erste Möglichkeit: Verwendung eines geeigneten Build-/Abhängigkeitstools statt Git


Ein Abhängigkeitsmanagementtool ist derzeit die von mir empfohlene Methode zum Umgang mit den wachsenden Problemen und den Build-Zeiten größerer Projekte.

Halte deine Module in individuellen Repositorys separat und verwalte ihre Interdependenzen mit einem Tool, das hierfür konzipiert wurde. Es ist für (nahezu) jeden Technologie-Stack eines auf dem Markt erhältlich. Einige Beispiele:

  • Maven (oder Gradle), wenn du Java verwendest
  • Npm für Node-Apps
  • Bower, Component.io etc., wenn du JavaScript verwendest (neu!)
  • Pip und requirements.txt, falls du mit Python arbeitest
  • RubyGems und Bundler, falls du mit Ruby arbeitest
  • NuGet für .NET
  • Ivy (oder eigene CMake-Aktionen) für C++ (neu!)
  • CocoaPods für Cocoa-iOS-Apps
  • Composer oder Phing für PHP (neu!)
  • Die Build/Abhängigkeits-Infrastruktur von Go ist ein Stück weit in die Programmiersprache integriert (allerdings wird gerade an einer umfassenderen Lösung gearbeitet, siehe godep). Für unseren Git-Server (Bitbucket Server) nutzen wir sowohl Maven als auch Bower. Wenn die Build-Zeit gekommen ist, führt das ausgewählte Tool einen Pull der richtigen Versionen der Abhängigkeiten durch, sodass der Build für dein Main-Projekt laufen kann. Einige dieser Tools haben Einschränkungen und machen suboptimale Annahmen. Sie haben sich aber bewährt und sind für diesen Zweck gut geeignet.

Die Probleme durch das Aufteilen eines Projekts

Zur Vereinfachung fasst man zu Beginn eines Projekts alles in einem Build zusammen. Mit zunehmender Größe des Projekts wird dein Build jedoch zu langsam und du musst "cachen". Jetzt kommt das Abhängigkeits-Management ins Spiel. Daher eignen sich Untermodule (im Folgenden mehr dazu) z. B. sehr gut für dynamische Programmiersprachen. Die meisten müssen sich irgendwann über Build-Zeiten Gedanken machen, daher denke ich, dass ein Tool zum Management von Abhängigkeiten sinnvoll ist.

Das Aufteilen von Komponenten in separate Repositorys bringt einige ernsthafte Schwierigkeiten mit sich. In unbestimmter Reihenfolge:

  • Zum Ändern einer Komponente ist ein Release erforderlich.
  • Es ist zeitaufwendig und kann aus den unerfindlichsten Gründen schiefgehen.
  • Man kommt sich bei kleinen Änderungen dumm vor.
  • Neue Builds müssen für jede Komponente manuell erstellt werden.
  • Das Finden von Repositorys wird erschwert.
  • Wenn nicht die gesamte Quelle in einem einzigen Repository zur Verfügung steht, wird refaktoriert.
  • In einigen Umgebungen (wie in unserer) ist für die Aktualisierung von APIs ein Meilenstein-Release des Produkts und dann des Plug-ins und anschließend wieder des Produkts erforderlich. Ich habe bestimmt einige Punkte vergessen, aber ich denke, du hast jetzt eine gute Vorstellung davon, dass eine perfekte Lösung für das Problem sicherlich anders aussieht.

Zweite Möglichkeit: git submodule


Wenn du kein Tool zum Abhängigkeits-Management nutzen willst oder kannst, bietet Git dir einen einfachen Weg, mit Untermodulen zu arbeiten. Untermodule können vor allem bei dynamischen Programmiersprachen praktisch sein. Langsame Builds ersparen sie dir allerdings nicht unbedingt. Ich habe ein paar Anhaltspunkte und Tipps dazu notiert und auch Alternativen entdeckt. Im Internet findet man jedoch größtenteils Argumente, die dagegensprechen.

1-zu1-Entsprechung von svn:external in Git

ACHTUNG! Wenn du auf der Suche nach einer gleichwertigen Lösung für svn:externals in Git bist, kannst du submodules verwenden. Mit submodules werden nur Release Branches und keine zufälligen Commits nachverfolgt.

Dritte Möglichkeit: Andere Tools für Build- und Stack-übergreifende Abhängigkeiten


Nicht immer hast du das Glück, an einem völlig homogenen Projekt zu arbeiten, das mit einem einzigen Tool fertiggestellt und zusammengesetzt werden kann. Zum Beispiel müssen bei einigen mobilen Projekten Abhängigkeiten von Java und C++ in Einklang gebracht oder anbieterspezifische Tools zur Erstellung von Ressourcen eingesetzt werden. In komplexeren Fällen kannst du Git auch noch erweitern. Ein tolles Beispiel hierfür ist das Repository von Android.

Andere Build-Tools, die einen näheren Blick wert sind:

Fazit und weiterführende Artikel


Weiterführende Informationen zur Build-Infrastruktur (und Maven) wurden von Charles O'Farrell vorgeschlagen – sehr gute Anregungen zum Nachdenken:

Zum Schluss noch ein großartiges Zitat aus dem letzten der oben angegebenen Artikel. Es bezieht sich zwar auf Maven, gilt aber ebenso für andere Build- und Abhängigkeitstools:

"Ein Cache macht nichts, außer Dinge zu beschleunigen. Du könntest einen Cache komplett entfernen und das umgebende System würde genauso funktionieren, nur langsamer. Ein Cache hat auch keine Nebenwirkungen. Egal, was du in der Vergangenheit mit einem Cache gemacht hast, eine bestimmte Abfrage an den Cache wird bei derselben Abfrage in der Zukunft denselben Wert zurückgeben.

Das Erlebnis mit Maven unterscheidet sich stark von dem, was ich beschreibe! Maven-Repositorys werden wie Caches verwendet, haben aber nicht die Eigenschaften von Caches. Wenn du etwas aus einem Maven-Repository abfragst, ist es sehr wichtig, was du in der Vergangenheit getan hast. Es gibt das Letzte zurück, was du hineingelegt hast. Wenn du etwas abfragst, bevor du es eingibst, wird das möglicherweise scheitern."

Nicola Paolucci

Nicola is an all-round hacker who loves exploring and teaching bleeding edge technologies. He writes and talks about Git, development workflows, code collaboration and more recently about Docker. Prior to his current role as Developer Instigator at Atlassian he led software teams, built crowd sourcing applications for geo-spacial data, worked on huge e-commerce deployments. Little known facts about Nicola: he gesticulates a lot while speaking (being Italian), lives in Amsterdam and rides a Ducati.


Diesen Artikel teilen

Lesenswert

Füge diese Ressourcen deinen Lesezeichen hinzu, um mehr über DevOps-Teams und fortlaufende Updates zu DevOps bei Atlassian zu erfahren.

Mitarbeiter arbeiten mit unzähligen Tools zusammen

Bitbucket-Blog

Abbildung: DevOps

DevOps-Lernpfad

Demo Den: Feature-Demos mit Atlassian-Experten

So funktioniert Bitbucket Cloud mit Atlassian Open DevOps

Melde dich für unseren DevOps-Newsletter an

Thank you for signing up