Wir machen Projekte, aber wir verwenden viel Code zwischen den Projekten wieder und haben viele Bibliotheken, die unseren gemeinsamen Code enthalten. Wenn wir neue Projekte implementieren, finden wir mehr Möglichkeiten, gemeinsamen Code herauszufiltern und in Bibliotheken abzulegen. Die Bibliotheken hängen voneinander ab, und die Projekte hängen von den Bibliotheken ab. Jedes Projekt und alle in diesem Projekt verwendeten Bibliotheken müssen dieselbe Version aller Bibliotheken verwenden, auf die sie sich beziehen. Wenn wir eine Software veröffentlichen, müssen wir Fehler beheben und möglicherweise für viele Jahre, manchmal für Jahrzehnte, neue Funktionen hinzufügen. Wir haben ungefähr ein Dutzend Bibliotheken, Änderungen betreffen häufig mehr als zwei Bibliotheken, und mehrere Teams arbeiten parallel an mehreren Projekten, wobei alle diese Bibliotheken gleichzeitig geändert werden.
Wir haben kürzlich auf git umgestellt und Repositorys für jede Bibliothek und jedes Projekt eingerichtet. Wir verwenden Stash als gemeinsames Repository, führen neue Funktionen für Feature-Zweige durch, stellen dann Pull-Anforderungen und führen diese erst nach Überprüfung zusammen.
Viele der Probleme, mit denen wir uns in Projekten befassen müssen, erfordern Änderungen in mehreren Bibliotheken und im spezifischen Code des Projekts. Dazu gehören häufig Änderungen an Bibliotheksschnittstellen, von denen einige nicht kompatibel sind. (Wenn Sie der Meinung sind, dass dies faul klingt: Wir arbeiten mit Hardware zusammen und verstecken bestimmte Hardware hinter generischen Schnittstellen. Fast jedes Mal, wenn wir die Hardware eines anderen Anbieters integrieren, stoßen wir auf Fälle, die unsere aktuellen Schnittstellen nicht erwartet haben, und müssen sie daher verfeinern.) Beispiel vorstellen , ein Projekt P1
der Bibliotheken L1
, L2
und L3
. L1
verwendet auch L2
und L3
und L2
verwendet L3
auch. Das Abhängigkeitsdiagramm sieht folgendermaßen aus:
<-------L1<--+
P1 <----+ ^ |
<-+ | | |
| +--L2 |
| ^ |
| | |
+-----L3---+
Stellen Sie sich nun vor, eine Funktion für dieses Projekt erfordert Änderungen in P1
und L3
die die Benutzeroberfläche von ändern L3
. Fügen Sie nun Projekte P2
und P3
in den Mix ein, die sich auch auf diese Bibliotheken beziehen. Wir können es uns nicht leisten, alle auf die neue Schnittstelle umzustellen, alle Tests auszuführen und die neue Software bereitzustellen. Was ist die Alternative?
- Implementieren Sie die neue Schnittstelle in
L3
- Machen Sie eine Pull-Anfrage für
L3
und warten Sie auf die Überprüfung - Führen Sie die Änderung zusammen
- Erstellen Sie eine neue Version von
L3
- Beginnen Sie mit der Arbeit an dem Feature in,
P1
indem Sie es auf dieL3
neue Version verweisen , und implementieren Sie dann das Feature imP1
Feature-Zweig - Stellen Sie eine Pull-Anfrage, lassen Sie diese überprüfen und zusammenführen
(Ich habe gerade bemerkt , dass ich zu wechseln vergessen L1
und L2
auf die neue Version. Und ich weiß nicht einmal , wo diese in bleiben, weil es mit parallel durchgeführt werden müßte P1
...)
Dies ist ein langwieriger, fehleranfälliger und sehr langer Prozess zur Implementierung dieser Funktion. Er erfordert unabhängige Überprüfungen (was die Überprüfung erheblich erschwert), lässt sich überhaupt nicht skalieren und wird uns wahrscheinlich aus dem Geschäft bringen, weil wir Seien Sie dabei so festgefahren, dass wir nie etwas erledigen.
Aber wie setzen wir Verzweigung und Tagging ein, um einen Prozess zu erstellen, mit dem wir neue Funktionen in neuen Projekten ohne allzu großen Aufwand implementieren können?
Antworten:
Hier wird das Offensichtliche herausgestellt, aber es lohnt sich vielleicht, es zu erwähnen.
Normalerweise werden Git-Repos pro Bibliothek / Projekt zugeschnitten, da sie in der Regel unabhängig sind. Sie aktualisieren Ihr Projekt und kümmern sich nicht um den Rest. Andere Projekte, die davon abhängen, aktualisieren einfach ihre Bibliothek, wann immer sie es für richtig halten.
Ihr Fall scheint jedoch stark von korrelierten Komponenten abhängig zu sein, sodass ein Merkmal normalerweise viele von ihnen betrifft. Und das Ganze muss als Bündel verpackt werden. Da für die Implementierung einer Funktion / Änderung / eines Fehlers häufig viele verschiedene Bibliotheken / Projekte gleichzeitig angepasst werden müssen, ist es möglicherweise sinnvoll, alle im selben Repo zu platzieren.
Dies hat starke Vor- und Nachteile.
Vorteile:
Nachteile:
Es liegt an Ihnen zu wissen, ob der Preis den Vorteil wert ist.
BEARBEITEN:
Es würde so funktionieren:
feature_x
feature_y
und wurdefeature_z
möglicherweise auch hinzugefügt. Es wird eine "teamübergreifende" Fusion. Deshalb ist es ein schwerwiegender Nachteil.Nur zur Veranschaulichung: Ich denke, dies ist in den meisten Fällen eine schlechte Idee und sollte mit Vorsicht durchgeführt werden, da der Nachteil der Zusammenführung normalerweise höher ist als der, den Sie durch Abhängigkeitsmanagement / ordnungsgemäße Funktionsverfolgung erhalten.
quelle
:-/
Darüber hinaus wissen selbst diejenigen, die es sind (und die auf den Wechsel zu Git drängten), nicht, wie wir unseren Entwicklungsprozess an Git anpassen können. Seufzer. Ich fürchte, es wird ein paar harte Monate dauern, bis die Dinge ruhiger werden. Trotzdem danke, deine ist die bisher hilfreichste Antwort.Die Lösung, die Sie suchen, ist ein Abhängigkeitsmanagement-Tool in Abstimmung mit Git-Submodulen
Tools wie:
Mit diesen Tools können Sie Abhängigkeiten eines Projekts definieren.
Sie können verlangen, dass ein Submodul mindestens Version > 2.xx ist, oder einen Bereich von Versionen angeben , die kompatibel sind = 2.2. * Oder weniger als eine bestimmte Version <2.2.3
Wenn Sie eine neue Version eines der Pakete veröffentlichen, können Sie diese mit der Versionsnummer versehen. Auf diese Weise können Sie diese bestimmte Version des Codes in alle anderen Projekte einbinden
quelle
Submodule
Sie sollten versuchen, Submodule zu aktivieren , wie in einem Kommentar vorgeschlagen.
Wenn Projekt
P1
auf die drei Submodule beziehtL1
,L2
undL3
speichert es tatsächlich einen Verweis auf bestimmte Commits in allen drei Repositories: diejenigen , die sind Arbeitsversionen der einzelnen Bibliotheken für dieses Projekt .So können mehrere Projekte mit mehreren Submodulen arbeiten: Sie
P1
beziehen sich möglicherweise auf die alte Version der Bibliothek,L1
während das ProjektP2
die neue Version verwendet.Was passiert, wenn Sie eine neue Version von liefern
L3
?L3
L2
funktioniert mitL3
, verpflichten, ...L1
funktioniert mit neuenL2
, ...P1
mit den neuen Versionen aller Bibliotheken funktioniert:P1
‚s lokale ArbeitskopieL1
,L2
undL3
, fetche die Änderungen , die Sie interessieren.git add L1 L2 L3
um den neuen Verweis auf Module festzuschreibenP1
, Test, Überprüfung, Pull-Anfrage, Zusammenführen ...Methodik
Ja, es sind unabhängige Überprüfungen erforderlich , da Sie Folgendes ändern:
Würden Sie aus dem Geschäft geraten, weil Sie Mist liefern? (Vielleicht eigentlich gar nicht). Wenn ja, müssen Sie Tests durchführen und Änderungen überprüfen.
Mit geeigneten Git-Tools (sogar
gitk
) können Sie leicht sehen, welche Versionen der Bibliotheken jedes Projekt verwendet, und Sie können sie unabhängig von Ihren Anforderungen aktualisieren. Submodule sind perfekt für Ihre Situation und verlangsamen Ihren Prozess nicht.Vielleicht können Sie einen Weg finden, einen Teil dieses Prozesses zu automatisieren , aber die meisten der oben genannten Schritte erfordern menschliches Gehirn. Der effektivste Weg, um Zeit zu sparen, besteht darin, sicherzustellen, dass Ihre Bibliotheken und Projekte einfach weiterzuentwickeln sind. Wenn Ihre Codebasis neue Anforderungen problemlos bewältigen kann, sind Codeüberprüfungen einfacher und nehmen wenig Zeit in Anspruch.
(Bearbeiten) Eine andere Sache, die Ihnen helfen könnte, ist das Gruppieren verwandter Codeüberprüfungen. Sie übernehmen alle Änderungen und warten, bis Sie diese Änderungen an alle Bibliotheken und Projekte weitergegeben haben, die sie verwenden, bevor Sie Pull-Anforderungen ausführen (oder bevor Sie sich um sie kümmern). Am Ende führen Sie eine größere Überprüfung für die gesamte Abhängigkeitskette durch. Vielleicht kann dies Ihnen helfen, Zeit zu sparen, wenn jede lokale Änderung klein ist.
quelle
Ich verstehe also, dass Sie für P1 die L3-Schnittstelle ändern möchten, aber Sie möchten, dass sich die anderen P2 und P3, die von der L3-Schnittstelle abhängen, sofort ändern. Dies ist ein typischer Fall von Abwärtskompatibilität. Es gibt einen schönen Artikel über die Wahrung der Abwärtskompatibilität
Es gibt verschiedene Möglichkeiten, dies zu lösen:
ODER
quelle
Wenn ich Ihr Problem richtig verstehe:
Das Ziel ist also, dass Sie P1 und L1 auf einmal und einen Monat später L2 und L3 auf einmal ausführen können.
In der Java-Welt ist dies trivial und möglicherweise die Standardarbeitsweise:
Sie können also den Code für L3 auf Ihrer lokalen Festplatte haben, der nicht kompiliert werden würde, wenn er gegen die Kopie von P1 im anderen Verzeichnis auf Ihrer Festplatte kompiliert würde. Zum Glück ist das nicht so. Java kann dies problemlos tun, da beim Kompilieren / Verknüpfen von Geschichten kompilierte JAR-Dateien und kein Quellcode verwendet werden.
Mir ist keine bereits vorhandene, weit verbreitete Lösung für dieses Problem in der C / C ++ - Welt bekannt, und ich würde mir vorstellen, dass Sie kaum die Sprache wechseln möchten. Aber etwas könnte leicht zusammen mit Make-Dateien gehackt werden, die das Gleiche tun:
Sie könnten sogar die C / C ++ - Unterstützung in maven verwenden , obwohl die meisten C-Entwickler Sie seltsam ansehen würden, wenn Sie ...
quelle
:)
Es gibt eine einfache Lösung: Release-Zweige über das gesamte Repository hinweg schneiden, alle Fixes mit allen aktiv ausgelieferten Releases zusammenführen (es ist einfach, wenn dies in Git möglich sein sollte).
Alle Alternativen werden im Laufe der Zeit und mit dem Projektwachstum ein schreckliches Durcheinander verursachen.
quelle