it-swarm.dev

Organisieren von Git-Repositorys mit allgemeinen verschachtelten Untermodulen

Ich bin ein großer Fan von Git-Submodulen . Ich möchte in der Lage sein, eine Abhängigkeit zusammen mit ihrer Version zu verfolgen, damit Sie auf eine frühere Version Ihres Projekts zurücksetzen und die entsprechende Version der Abhängigkeit haben können, um sie sicher und sauber zu erstellen. Darüber hinaus ist es einfacher, unsere Bibliotheken als Open-Source-Projekte freizugeben, da der Verlauf der Bibliotheken von dem der Anwendungen abhängt, die von ihnen abhängen (und die nicht aus Open-Source-Quellen stammen).

Ich richte den Workflow für mehrere Projekte bei der Arbeit ein und habe mich gefragt, wie es wäre, wenn wir diesen Ansatz etwas extrem verfolgen würden, anstatt nur ein einziges monolithisches Projekt zu haben. Ich erkannte schnell, dass es in wirklich eine potenzielle Dose Würmer gibt, die Submodule verwenden.

Angenommen, ein Anwendungspaar: studio und player und abhängige Bibliotheken core, graph und network, wobei die Abhängigkeiten wie folgt sind:

  • core ist eigenständig
  • graph hängt von core ab (Untermodul bei ./libs/core)
  • network hängt von core ab (Untermodul bei ./libs/core)
  • studio hängt von graph und network ab (Untermodule bei ./libs/graph und ./libs/network)
  • player hängt von graph und network ab (Untermodule bei ./libs/graph und ./libs/network)

Angenommen, wir verwenden CMake und jedes dieser Projekte verfügt über Komponententests und alle Arbeiten. Jedes Projekt (einschließlich studio und player) muss eigenständig kompiliert werden können, um Codemetriken, Komponententests usw. durchzuführen.

Die Sache ist, ein rekursives git submodule fetch, dann erhalten Sie folgende Verzeichnisstruktur:

studio/
studio/libs/                    (sub-module depth: 1)
studio/libs/graph/
studio/libs/graph/libs/         (sub-module depth: 2)
studio/libs/graph/libs/core/
studio/libs/network/
studio/libs/network/libs/       (sub-module depth: 2)
studio/libs/network/libs/core/

Beachten Sie, dass core im Projekt studio zweimal geklont wird. Abgesehen von dieser Verschwendung von Speicherplatz habe ich ein Problem mit dem Buildsystem, da ich core zweimal erstelle und möglicherweise zwei verschiedene Versionen von core erhalte.

Frage

Wie organisiere ich Submodule so, dass ich die versionierte Abhängigkeit und den eigenständigen Build erhalte, ohne mehrere Kopien allgemeiner verschachtelter Submodule zu erhalten?

Mögliche Lösung

Wenn die Bibliotheksabhängigkeit eher ein Vorschlag ist (dh "bekanntermaßen mit Version X funktioniert" oder "nur Version X wird offiziell unterstützt") und potenziell abhängige Anwendungen oder Bibliotheken für die Erstellung mit einer beliebigen Version verantwortlich sind, dann Ich könnte mir folgendes Szenario vorstellen:

  • Lassen Sie sich vom Build-System für graph und network mitteilen, wo core zu finden ist (z. B. über einen Compiler-Include-Pfad). Definieren Sie zwei Build-Ziele, "Standalone" und "Dependency", wobei "Standalone" auf "Dependency" basiert und den Include-Pfad hinzufügt, der auf das lokale core-Untermodul verweist.
  • Führen Sie eine zusätzliche Abhängigkeit ein: studio on core. Dann erstellt studiocore, legt den Include-Pfad auf eine eigene Kopie des Untermoduls core fest und erstellt dann graph und network im "Abhängigkeits" -Modus.

Die resultierende Ordnerstruktur sieht folgendermaßen aus:

studio/
studio/libs/                    (sub-module depth: 1)
studio/libs/core/
studio/libs/graph/
studio/libs/graph/libs/         (empty folder, sub-modules not fetched)
studio/libs/network/
studio/libs/network/libs/       (empty folder, sub-modules not fetched)

Dies erfordert jedoch etwas Magie des Build-Systems (ich bin ziemlich sicher, dass dies mit CMake möglich ist) und ein wenig manuelle Arbeit seitens der Versionsaktualisierungen (das Aktualisieren von graph erfordert möglicherweise auch das Aktualisieren von core und network, um eine kompatible Version von core in allen Projekten zu erhalten).

Irgendwelche Gedanken dazu?

50
André Caron

Ich bin sehr spät zu dieser Party, aber Ihre Frage scheint immer noch keine vollständige Antwort zu haben, und es ist ein ziemlich prominenter Hit von Google.

Ich habe genau das gleiche Problem mit C++/CMake/Git/Submodules und ich habe ein ähnliches Problem mit MATLAB/Git/Submodules, das etwas seltsamer wird, weil MATLAB nicht kompiliert ist. Ich bin vor kurzem auf dieses Video gestoßen, was eine "Lösung" vorzuschlagen scheint. Ich mag die Lösung nicht, weil es im Wesentlichen bedeutet, Submodule wegzuwerfen, aber es beseitigt das Problem. Es ist genau so, wie es @errordeveloper empfiehlt. Jedes Projekt hat keine Submodule. Um ein Projekt zu erstellen, erstellen Sie ein Superprojekt, um es zu erstellen, und fügen Sie es als Geschwister zu seinen Abhängigkeiten hinzu.

Ihr Projekt zur Entwicklung von graph könnte also folgendermaßen aussehen:

buildgraph/graph
buildgraph/core

und dann könnte Ihr Projekt für Studio sein:

buildstudio/studio
buildstudio/graph
buildstudio/network
buildstudio/core

Die Superprojekte sind nur ein Haupt- CMakeLists.txt Und eine Reihe von Submodulen. Aber keines der Projekte hat selbst Submodule.

Die einzigen Kosten, die ich für diesen Ansatz sehe, sind die Verbreitung trivialer "Superprojekte", die nur dem Aufbau Ihrer realen Projekte gewidmet sind. Und wenn jemand eines Ihrer Projekte in die Hand nimmt, gibt es keine einfache Möglichkeit, ohne das Superprojekt zu finden, welche Abhängigkeiten es hat. Das könnte es zum Beispiel wirklich hässlich auf Github machen.

5
chadsgilbert

Ich nehme an, wenn Sie sowohl graph als auch network Submodule in studio integrieren, müssen Sie zu einem bestimmten Zeitpunkt im Verlauf immer dieselbe Version von core haben von studio. Ich würde das studio/libs/core Submodul in studio/libs/{graph,network}/libs.

Aktualisieren:

Ich habe mehrere Repositorys mit den von Ihnen angegebenen Abhängigkeiten erstellt:

./core      <--- (v2)
./graph
./graph/libs
./graph/libs/core  <--- (v2)
./graph/.gitmodules
./network
./network/libs
./network/libs/core  <--- (v1)
./network/.gitmodules
./studio
./studio/libs
./studio/libs/graph
./studio/libs/graph/libs
./studio/libs/graph/libs/core <--- (v1)
./studio/libs/graph/.gitmodules
./studio/libs/network
./studio/libs/network/libs
./studio/libs/network/libs/core  <--- (v1)
./studio/libs/network/.gitmodules
./studio/studio
./studio/.gitmodules

v1 und v2 sind zwei verschiedene Versionen von core. graph behandelt Version 2, während network einige Arbeit benötigt und bei Version 1 hängen bleibt. In studio zeigen die lokal eingebetteten Versionen von core beide auf v1 um ein Arbeitsprogramm zu haben. Abgesehen von der Build-Perspektive funktioniert jetzt alles gut mit Submodulen.

Ich kann jetzt das folgende Verzeichnis entfernen:

./studio/libs/network/libs/core

Und ersetzen Sie es durch einen symbolischen Link:

./studio/libs/network/libs/[email protected] -> ../../graph/libs/core/

Ich begebe diese Änderung lokal und verliere die Fähigkeit, zwei separate Versionen von core in studio zu haben, aber ich erstelle core nur einmal. Wenn ich bereit bin, auf v2, Ich kann :

 git submodule update # (--rebase ?)

... in Studio/Libs/Netzwerk.

1
coredump

Ich würde keine Submodule verwenden.

Es ist verlockend, wie es früher bei svn-externals der Fall war. Können Sie jedoch sicher sein, dass sich alle von Ihnen verknüpften Projekte in einem Jahr immer noch am selben Ort befinden? Was ist mit in fünf?

Daher kopiere ich einfach alle erforderlichen Abhängigkeiten in mein Projekt. Dies bedeutet, dass ich den genauen Status überprüfen kann, solange mein Repo gültig ist.

Grundsätzlich habe ich eine Ordnerstruktur wie folgt:

myproject/... [sources etc]
ext/ [third-party dependencies]


e.g. ext/boost, ext/cppunit

Obwohl dies aus Sicht des Speicherplatzes nicht sehr schön ist, schätze ich die Garantie, dass ich jeden aufgezeichneten Status überprüfen kann, solange das Repo viel höher verfügbar ist.

Darüber hinaus gibt es eine Reihe von Problemen mit Submodulen, wie beschrieben hier

0
Wilbert

Ich würde es reduzieren, um eine Submodultiefe von nur einem zu haben, und ein Repository haben, das alle Module als Submodule und nichts anderes als README und die Build-Skripte) enthält Seien Sie ein separates Build-Skript für jedes der Pakete, die seine Abhängigkeiten verknüpfen. Andernfalls können Sie ein separates Repo für ein Paket erstellen.

0
errordeveloper

Hier steht genau das gleiche Problem. Eine der Lösungen könnte darin bestehen, ein Repo libs zu haben, das core, network, graph als Submodule und nur CMakeLists enthält, die jede der Bibliotheken mitteilen wo man seine Abhängigkeiten findet. Jede Anwendung würde jetzt libs als Submodul haben und nur die erforderlichen Bibliotheken verwenden.

Das Testen jeder Bibliothek kann auf zwei Arten eingerichtet werden:

  • Haben Sie core_testing, graph_testing, network_testing als separate Anwendungen
  • Stellen Sie getestete Bibliotheken auf Testservern bereit und finden Sie sie, während Sie Tests mit cmake ausführen
0
Max