Blog

Monorepos für echtes CI

Arjan Molenaar

Aktualisiert Oktober 22, 2025
5 Minuten

Am 15. und 16. April fand die CITCON Europe in Cluj-Napoca (Transsylvanien) statt. Die CITCON ist eine Open-Spaces-Konferenz. Die Tagesordnung wird von den Konferenzteilnehmern selbst zusammengestellt. Daher gibt es immer ein paar nette Mitbringsel. In diesem Jahr stellte Ivan Moore(@ivanrmoore) die Behauptung auf, dass Sie ohne Monorepos keine CI betreiben können. Ein Monorepo ist einfach ein Repository, in dem der gesamte Quellcode landet. Dies steht im Gegensatz zu einer Einrichtung mit (zum Beispiel) Git Source Control, bei der Sie ein einzelnes Repository pro Modul haben. Die Idee, ein einziges (großes) Repository mit dem gesamten Code zu haben, erscheint seltsam. Nach einer gründlichen Diskussion waren mir die Vorzüge von Monorepos klar.

Nehmen wir ein Szenario mit 2 Diensten, die von einem Modul mit gemeinsamem Code abhängen. Jeder Dienst muss die Version des gemeinsamen Moduls selbst verwalten - daher werden die letzten Änderungen am gemeinsamen Modul nicht in die Dienste integriert. Jetzt erhöhen Sie die Version des gemeinsamen Moduls.

Multi-Repo Ganz zu schweigen von der Buchhaltung, die Sie erledigen müssen, wenn Sie sie brauchen
  1. Entwicklung einiger allgemeiner Funktionen in Service 1
  2. Sobald es für Service 1 funktioniert, verschieben Sie den Code in das gemeinsame Repo
  3. Erstellen Sie die Freigabe des Repos
  4. Aktualisieren Sie die Version des gemeinsamen Moduls in Dienst 1
  5. Aktualisieren Sie eventuell die Version des gemeinsamen Moduls in Dienst 2
Wenn Schritt 5 schief geht, müssen wir das gemeinsame Modul reparieren, was zu einer weiteren Veröffentlichung führt. Nun, Sie verstehen schon. Modul 2 wird zu spät integriert. Wenn sich die Dienste 1 und 2 und das gemeinsame Modul im selben Repository befinden, wird das Leben einfacher: Es gibt nur eine Version des gemeinsamen Moduls, die berücksichtigt werden muss: diejenige in Ihrem aktuellen Zweig. Das bedeutet, dass der Build sofort abbricht, wenn eine inkompatible Änderung eingecheckt wurde (== schnelles Feedback, yay!). Außerdem wird dadurch Code-Duplizierung vermieden: ein unzusammenhängendes gemeinsames Modul liegt in jedermanns Verantwortung = niemand wird die volle Verantwortung übernehmen. Irgendwann wird es einfacher, Funktionen zu erstellen und sie nicht in das gemeinsame Modul zu verschieben, sondern sie in Service 2 zu replizieren. Alles an einem Ort zu haben, macht es einfacher, Code zu refaktorisieren, doppelten Code zu finden und sogar strukturelle Änderungen an allen Modulen in Ihrem Repo vorzunehmen. Eine sehr wichtige Funktion, die monorepos bietet, ist die Wiederholbarkeit: Wenn Sie sich auf Snapshot-Versionen verlassen, können die Ergebnisse im Laufe der Zeit je nach aktueller Snapshot-Version variieren. Selbst wenn Sie alle Builds markieren, frisst das eine Menge Ressourcen, wenn ein Großteil der Binärdateien nie verwendet wird. Bei monorepos wird die Version (der Zustand) der Anwendung durch einen Commit-Hash/eine Revisionsnummer bestimmt. Es ist erwähnenswert, dass Unternehmen wie Google und Facebook dies auf die Spitze treiben: Der gesamte Quellcode für das gesamte Unternehmen landet in einem Repo, einschließlich des Codes von Drittanbietern. Ich würde annehmen, dass es ein guter Anfang ist, den gesamten Code für Ihr aktuelles Projekt in ein Repo zu packen (fangen Sie klein an) und die Auflösung externer Abhängigkeiten so zu lassen, wie sie ist. Dies würde größere Refactorings fördern und die Wiederverwendung des Codes verbessern, während Sie sich den Ärger mit dem Versions-Upgrade ersparen. Wie sieht es nun mit den Nachteilen dieses Ansatzes aus?
  1. Das Repository kann ziemlich groß werden. Dies verlangsamt nur den ersten Checkout[1]. Es würde aber wahrscheinlich mehr Zeit in Anspruch nehmen, eine Reihe von Repos auszuchecken.
  2. Wird das Repository langsam werden? Nun, der Linux-Kernel wird in einem einzigen Repository verwaltet. Wenn Ihre Codebasis so viele Codezeilen umfasst (derzeit etwa 17 Millionen), können Sie entscheiden, ob es sinnvoll ist, die Codebasis aufzuteilen oder in Werkzeuge zu investieren.
  3. Jeder kann jeden Code ändern. Ja, natürlich! Deshalb haben Sie ja auch die Versionskontrolle. Das Wichtigste ist, dass Sie die Codeänderungen verfolgen und sehen können, wer sie vorgenommen hat.
  4. Alle pushen den gesamten Code in ein Repository, so dass Sie die ganze Zeit aktualisieren/ziehen/rebasieren müssen. In der Praxis erweist sich dies nicht als wirkliches Problem: Wenn Sie Pull Requests verwenden, ist die Anzahl der Commits auf dem Master-Zweig nicht so groß. Wenn Sie eine trunk-basierte Entwicklung betreiben ( ), integrieren Sie ständig alles. Es gibt keine Überschneidungen zwischen Code, der für Service 1 und Service 2 übertragen wurde, d.h. es gibt keine Merge-Konflikte.
  5. Sie müssen Ihre CI-Builds auf intelligente Weise einrichten, so dass nicht alles bei jedem Commit gebaut wird. Moderne Build-Tools können damit umgehen. Wenn nicht, müssen Sie ein Skript schreiben, das diese Aufgabe übernimmt. Das ist kein Problem, denn es wird in dasselbe Repository übertragen und ist daher immer auf dem neuesten Stand mit dem Rest des Codes.
Alles in allem bin ich ziemlich überzeugt, dass die Vorteile die Nachteile überwiegen. Wenn ich mir die Projekte anschaue, die ich in den letzten Jahren durchgeführt habe, würde jedes einzelne von ihnen von der Verwendung eines Monorepos anstelle eines Pro-Modul-Repos profitieren. Außerdem: Moderne IDEs wie IntelliJ und Eclipse können diese Art von Quellcode-Abhängigkeiten aussortieren. Änderungen im gemeinsamen Modul können zu Fehlern in den Servicemodulen führen. Obwohl dies die Abhängigkeiten für einen Entwickler bis zu einem gewissen Grad löst, ist es keine Lösung, auf die sich ein komplettes Team verlassen kann. [1] CI-Server können oberflächliche Checkouts durchführen, so dass es hier keine Belastung gibt.

Verfasst von

Arjan Molenaar

Contact

Let’s discuss how we can support your journey.