Die Git-Monorepo neu denken: Eine CAS-native Architektur für Menschen und Coding-Agenten

Jede wachsende Engineering-Organisation muss sich irgendwann zwischen vielen Repositories und einem einzigen entscheiden. Man beginnt mit Dutzenden kleiner Repositories, und zunächst wirkt alles einfach. Jede Bibliothek hat ihren eigenen Issue-Tracker, ihre eigene CI-Pipeline und einen git clone, der in Sekunden abgeschlossen ist. Dann ändert man eine Struktur in einem zentralen Networking-Paket und verbringt den Rest des Nachmittags damit, Pull Requests für Versionsanhebungen in sechs nachgelagerten Repositories zu öffnen und darauf zu warten, dass die CI-Warteschlangen in topologischer Reihenfolge abgearbeitet werden.
Verschiebt man alles in ein klassisches Git-Monorepo, tauscht man die Koordination zwischen Repositories gegen die Größe des Repositories ein. Mit wachsender Commit-Historie und sich ansammelnden Binärdateien in früheren Revisionen wird git fetch langsamer. Working Trees schwellen auf Gigabytes an. Bald schlägt jemand vor, einen eigenen Virtual-Filesystem-Daemon, einen dedizierten Code-Review-Server oder eine Flotte entfernter Build-Worker aufzusetzen, nur damit die tägliche Entwicklung erträglich bleibt.
Kommen autonome Coding-Agenten ins Team, verschärfen sich beide Fehlerbilder. Polyrepos blenden einen Agenten gegenüber projektübergreifenden Aufrufern aus und zwingen ihn, Zugangsdaten über mehrere Repositories hinweg zu verwalten. Klassische Monorepos belasten bei jeder Aufgabeninitialisierung den Festplattenspeicher des Agenten-Containers und die Netzwerkbandbreite, während parallel arbeitende Agenten, die denselben Branch verändern, endlose Rebase-Wettläufe erzeugen.
Inspiriert von der Architektur von google3, haben wir einen Single-Trunk-Ansatz mit atomaren Änderungen, sparsames Onboarding in unter einer Sekunde, hierarchische OWNERS-Governance sowie eigenständige Open-Source-Spiegel mit Standard-Git-Mechanismen und handelsüblichem Objektspeicher umgesetzt.
Das Design benötigt weder einen eigenen Filesystem-Daemon noch eine Review-Appliance von Drittanbietern, denn es behandelt Git als Content-Addressable Store (CAS) auf Basis eines Merkle-Trees.
Die Fehlannahme im Kern langsamer Git-Monorepos
Wenn Entwickler klagen, Git skaliere nicht für große Monorepos, stoßen sie selten auf eine Grenze der Objektdatenbank von Git. Innerhalb von .git/objects speichert Git drei unveränderliche Grundelemente, die über ihren SHA-1- (oder SHA-256-) Inhalts-Hash identifiziert werden:
blob: Die rohen Bytes einer einzelnen Datei.tree: Eine Verzeichnisliste, die Dateinamen und Berechtigungen aufblob- oder untergeordnetetree-Hashes abbildet.commit: Ein kleiner Textheader (typischerweise 200 bis 300 Byte), der auf genau einen Root-tree-Hash, null oder mehr Eltern-commit-Hashes und Autorenmetadaten verweist.
Enthält ein Monorepo 50.000 Dateien und bearbeitet man eine einzelne Zeile in einer Datei, verwendet der neue Commit die exakt gleichen blob- und tree-Hashes für die übrigen 49.999 Dateien.
Ein klassisches Git-Monorepo fühlt sich schwerfällig an, weil die Konvention eine einzige Referenz, refs/heads/main, mit drei kollidierenden Aufgaben belastet:
- Sie hält den gesamten einheitlichen Verzeichnisbaum jedes Projekts.
- Sie zieht die gesamte über Eltern verknüpfte Kette historischer Commits bis zum ersten Tag mit.
- Sie liegt innerhalb von
refs/heads/*, dem Namensraum, den Git-Server standardmäßig bei jedemgit cloneundgit fetchankündigen und aushandeln.
Jedes Mal, wenn ein Entwickler oder CI-Runner refs/heads/main abruft, handeln Client und Server die Erreichbarkeit im Commit-Graphen über Tausende historischer Revisionen aus. Hat jemand vor drei Jahren versehentlich ein 100 MB großes Archiv committet und am nächsten Tag wieder gelöscht, hängt dessen blob weiterhin an einem historischen tree, der von refs/heads/main aus erreichbar ist.
Trennung des Referenz-Namensraums
Das Wire-Protokoll von Git kündigt bei einem Standard-Clone nur refs/heads/* und refs/tags/* an. Referenzen unter eigenen Namensräumen wie refs/trunk/* oder refs/ws/* liegen im selben Objektspeicher des Servers, profitieren von derselben Packfile-Delta-Kompression und können explizit abgerufen oder gepusht werden. Gleichzeitig verursachen sie bei Standard-Clones keinerlei Mehraufwand.
Die Aufteilung dieser Aufgaben auf getrennte Referenzen innerhalb eines einzigen Repositories beseitigt den Engpass:
1refs/heads/main Nur Control Plane (~20 KB: Regeln, .gitconfig, Sync-Konfiguration, Skripte)
2refs/trunk/main Commit-Snapshot ohne Parent, der auf den neuesten einheitlichen Root-Tree zeigt
3refs/trunk/history Lineare Commit-Kette mit Parent-Verknüpfung, die exakt denselben Root-Tree-SHA-1 teilt
4refs/ws/<actor>/<id> Isolierte Workspace-Snapshots (Changelists) pro Entwickler oder Agent
5refs/ws/cl/<change-id>/<tip> Unveränderliche Patchsets: jeder Tip einer Änderung, der zum Review eingereicht wurde
6refs/heads/land/<id> Ephemerer Trigger der Merge-Queue, der nach dem Landen sofort gelöscht wird
1. Die Control Plane (refs/heads/main)
Der Standard-Branch enthält keinen Anwendungsquellcode. Er verfolgt nur die Betriebsregeln des Repositories (AGENTS.md, README.md), eine gemeinsame .gitconfig mit Workflow-Aliasen, die Starlark-Synchronisationskonfiguration (sync.star) und serverseitige Merge-Skripte. Das Klonen des Standard-Branches überträgt etwa 20 KB und ist in Millisekunden abgeschlossen.
2. Der parentlose Trunk-Snapshot (refs/trunk/main)
refs/trunk/main zeigt auf den vollständigen, einheitlichen Quellbaum der gesamten Organisation (//web/*, //net/*, //ipc/*, //storage/*, //crypto/*, //ai/*, //devtools/*, //corp/*, //third_party/*, //experimental/*). Sein Commit-Objekt wird jedoch ohne das Flag -p für Eltern erstellt.
Da refs/trunk/main keine Eltern besitzt (parents = []), erfordert der Abruf keinerlei Aushandlung des Commit-Graphen. Der Git-Server durchläuft keine Historie; er sendet den einzelnen Head-Commit und seine aktuellen Verzeichnis-tree-Objekte. Historische Binärdateien oder gelöschte Dateien aus dem letzten Monat sind von refs/trunk/main aus nicht erreichbar und werden niemals übertragen.
3. Die lineare Audit-Historie (refs/trunk/history)
Entwickler benötigen weiterhin git blame und git log, wenn sie Regressionen untersuchen. Jedes Mal, wenn eine Änderung landet, erzeugt das Merge-Skript zwei Commit-Objekte, die auf denselben exakten Root-Tree $NEW_TREE mit dem SHA-1-Hash verweisen:
1# Commit-Snapshot ohne Parent für sofortige Workspace-Checkouts der Tiefe 1
2SNAP=$(git commit-tree "$NEW_TREE" -m "$RAW_MSG")
3
4# Commit mit Parent-Verknüpfung für lineares git log und git blame
5HIST=$(git commit-tree "$NEW_TREE" -p "$OLD_HIST" -m "$RAW_MSG")
6
7git push --atomic origin \
8 --force-with-lease="refs/trunk/main:${OLD_MAIN}" \
9 --force-with-lease="refs/trunk/history:${OLD_HIST}" \
10 "${SNAP}:refs/trunk/main" \
11 "${HIST}:refs/trunk/history"
Die Beibehaltung sowohl von refs/trunk/main als auch von refs/trunk/history verdoppelt den Speicherbedarf nicht. Da beide Commits denselben $NEW_TREE-Hash referenzieren, dedupliziert der Content-Addressable Store von Git 100 % der tree- und blob-Objekte. Die zusätzlichen Speicherkosten des parentlosen Snapshots betragen lediglich einen Commit-Header von 250 Byte.
4. Isolierte Workspaces (refs/ws/<actor>/<id>)
Arbeitsbranches in Bearbeitung werden nach refs/ws/<actor>/<id> statt nach refs/heads/* gepusht. Hundert Coding-Agenten können jede Minute Checkpoints speichern, ohne die Branch-Auswahl zu verunreinigen oder git fetch für menschliche Ingenieure zu verlangsamen.
Onboarding in vier Schritten: So funktioniert Sparse- und Blobless-Checkout
Mit diesem Referenzlayout installiert ein neuer Entwickler oder ein ephemerer Coding-Agent-Container weder eine eigene CLI noch einen FUSE-Treiber. Das Onboarding umfasst vier Schritte mit Standard-Git und den Aliasen des Repositories:
1# 1. Die 20 KB große Control Plane mit aktiviertem Blob-Filter und Sparse-Modus klonen
2git clone --filter=blob:none --sparse https://github.com/example-org/monorepo.git
3cd monorepo
4
5# 2. Repository-Aliase laden und refs/trunk/* anbinden
6git config include.path ../.gitconfig
7git trunk-init
8
9# 3. Die für diese Aufgabe benötigten Domänenverzeichnisse deklarieren
10git sparse-checkout set net/relay ipc/codec
11
12# 4. Einen isolierten Workspace anlegen, der auf dem neuesten Trunk-Snapshot basiert
13git ws-new alice/optimize-framing
Jeder Schritt lädt nur das, was er benötigt:
git clone --filter=blob:none --sparselädt die 20 KB große Control Plane aufrefs/heads/mainherunter.git trunk-initkonfiguriert+refs/trunk/*:refs/remotes/origin/trunk/*und führt einen Blobless-Fetch aus. Git lädt dietree-Metadaten fürrefs/trunk/main(typischerweise einige Dutzend Kilobyte) und keine einzige Datei-blob.git sparse-checkout set net/relay ipc/codecweist den Cone-Mode-Index-Filter von Git an, nur das Root-Verzeichnis und diese beiden Teilbäume zu materialisieren.git ws-newwechselt zu einem neuen Branch, der auforigin/trunk/mainbasiert. Git fordert anschließend nur bei Bedarf dieblob-Objekte innerhalb vonnet/relayundipc/codecan. Die übrigen 95 % des Monorepos werden nie auf die Festplatte geladen.
Ausblick: refs/trunk/main als Virtual Filesystem (VFS) einbinden
Sparse-Checkout mit Blobless-Clones deckt die täglichen Arbeitsabläufe ohne zusätzliche Client-Werkzeuge ab. Da refs/trunk/main bereits ein reiner Merkle-Tree in einem Content-Addressable Store ist, bietet die Architektur außerdem eine direkte Grundlage für ein optionales Virtual Filesystem (VFS) im Userspace über FUSE unter Linux, FileProvider unter macOS oder ProjFS unter Windows:
- Sofortiges Einbinden des vollständigen Baums: Ein leichtgewichtiger lokaler Mount-Daemon liest das Root-
tree-Objekt vonrefs/trunk/mainund projiziert die gesamte Verzeichnishierarchie des Monorepos innerhalb von Millisekunden in das Arbeitsverzeichnis. Ein Aufruf vongit sparse-checkout setentfällt damit. - Bedarfsgesteuertes Nachladen von Blobs: Dateiinhalte bleiben virtuell, bis ein Compiler, eine IDE oder ein Agent einen Systemaufruf
open(2)oderread(2)ausführt. Der Daemon lädt dann den entsprechenden SHA-1-blobvom CAS-Endpunkt und legt ihn auf lokalem NVMe-Speicher zwischen. - Copy-on-Write-Overlay für Workspaces: Lokale Änderungen werden in eine leichtgewichtige obere Overlay-Schicht geschrieben. Der Aufruf von
git ws-savehasht nur die veränderten Pfade in diesem Overlay, schreibt die aktualisiertenblob- undtree-Objekte und pusht den resultierenden Commit nachrefs/ws/<actor>/<id>, ohne unveränderte Verzeichnisse zu durchsuchen.
Das Changelist-Modell auf reinem Git: serverseitiges Landen im Speicher
Im klassischen Git-Workflow erzeugt das Zusammenführen eines Feature-Branches entweder einen Merge-Commit mit zwei Eltern, der die Historie nichtlinear macht, oder die Entwickler müssen manuell rebasen und mit parallelen Pushes auf main um die Wette laufen.
Inspiriert vom Changelist-(CL-)Modell von google3, repräsentiert in unserer Architektur jeder Workspace eine einzelne atomare Änderung gegenüber dem Trunk-Snapshot. Während ein Entwickler oder Agent lokal in ws/alice/optimize-framing arbeitet, kann er zehn inkrementelle Commits erstellen (wip, fix tests, lint). Ist die Änderung bereit zum Landen, faltet der Server das Workspace-Delta zu einer einzigen linearen Trunk-Revision zusammen, ohne auf dem CI-Runner jemals ein Arbeitsverzeichnis auszuchecken.
So führt das Landing-Skript (land.sh) die Operation im Speicher mit den Plumbing-Befehlen von Git 2.40+ aus:
1# 1. Den Root-Snapshot-Commit ermitteln, von dem der Workspace abgezweigt wurde
2BASE=$(git rev-list --max-parents=0 "$WORK_SHA")
3
4BASE_TREE=$(git rev-parse "${BASE}^{tree}")
5MAIN_TREE=$(git rev-parse "${OLD_MAIN}^{tree}")
6WORK_TREE=$(git rev-parse "${WORK_SHA}^{tree}")
7
8# 2. Den zusammengeführten Root-Tree im Speicher berechnen, ohne Working-Tree-Checkout
9if [ "$MAIN_TREE" = "$BASE_TREE" ]; then
10 NEW_TREE="$WORK_TREE"
11elif OUT=$(git merge-tree --write-tree --merge-base="$BASE_TREE" "$MAIN_TREE" "$WORK_TREE"); then
12 NEW_TREE=$(head -n1 <<<"$OUT")
13else
14 echo "Merge conflict detected; run git ws-sync to rebase." >&2
15 exit 1
16fi
In Schritt 2 gilt:
- Unabhängig davon, wie viele lokale Commits auf dem Workspace-Branch entstanden sind, vergleicht das Skript nur drei Tree-Hashes: den ursprünglichen Basis-Snapshot (
$BASE_TREE), den aktuellen Trunk-Snapshot ($MAIN_TREE) und den finalen Workspace-Tree ($WORK_TREE). - Wenn
refs/trunk/mainin//web/blogvorangeschritten ist, während Alice//net/relaybearbeitet hat, berechnetgit merge-tree --write-treeden kombinierten Root-Tree$NEW_TREEdirekt im Objektspeicher von Git innerhalb von Millisekunden, ohne Dateien auf das Dateisystem des Runners zu schreiben. - Nachdem die unten beschriebenen Richtlinienprüfungen bestanden sind, aktualisiert ein einzelner
git push --atomicmit--force-with-leasedie Referenzrefs/trunk/main, hängt einen linearen Commit anrefs/trunk/historyan, und der Landing-Triggerrefs/heads/land/<id>wird gelöscht.
Durchsetzung von Architekturgrenzen: vierstufige Sichtbarkeit und hierarchische OWNERS
Das Zusammenführen von Code in ein einziges Repository funktioniert nur, wenn die Grenzen zwischen den Domänen mechanisch durchgesetzt werden, bevor ein Commit landen darf. Unmittelbar nachdem git merge-tree --write-tree den $NEW_TREE erzeugt hat (und bevor git push --atomic den Trunk aktualisiert), führt unsere Richtlinien-Engine zwei Prüfungen mit einem Aufwand von O(Delta) über git diff-tree "$MAIN_TREE" "$NEW_TREE" aus.
1. Vierstufige Domänensichtbarkeit
Der Root-Tree ist in vier Sichtbarkeitsstufen unterteilt:
| Verzeichnispräfix | Stufe | Erlaubte Importe | Verbotene Importe | OWNERS-Gate |
|---|---|---|---|---|
//web/*, //net/*, //ipc/*, //storage/*, //crypto/*, //ai/*, //devtools/* | Öffentliche Produktion | Öffentliche Produktion, //third_party/* | //corp/*, //experimental/* | Erzwungen |
//third_party/* | Externer Anbieter | In sich geschlossen oder //third_party/* | Alle Domänen außer third_party | Erzwungen |
//corp/* | Interner Bereich | Öffentliche Produktion, //corp/*, //third_party/* | //experimental/* | Erzwungen |
//experimental/<actor>/* | Sandbox | Jedes Paket außer corp | //corp/* | Ausgenommen (automatisch genehmigt) |
Versucht ein öffentliches Paket in //web/*, ein internes Paket aus //corp/* oder einen nicht überführten Prototyp aus //experimental/* zu importieren, bricht der Landing-Job ab, bevor refs/trunk/main angefasst wird.
2. Hierarchische OWNERS-Prüfung ohne Gerrit-Server
Der Verifizierer erzwingt verzeichnisbezogene OWNERS-Dateien mit Vererbungsregeln:
- Für jeden Pfad, der zwischen
$MAIN_TREEund$NEW_TREEgeändert wurde, durchläuft der Verifizierer das Verzeichnis der Datei aufwärts bis//OWNERS. - Jede
OWNERS-Datei kann mitset noparentvererbte Genehmigungen aus übergeordneten Verzeichnissen blockieren oder mitper-file *.sql=@dba-teamGenehmigungen über Dateinamen-Glob-Muster eingrenzen. - Invariante gegen Manipulation: Bestehende
OWNERS-Dateien werden stets aus$MAIN_TREE(dem aktuellen Trunk-Tree) gelesen, niemals aus$NEW_TREE. Ein nicht genehmigter Autor kann sich keine Berechtigung verschaffen, indem erOWNERSim selben Workspace-Commit bearbeitet. - Ausnahme für Sandboxes: Jeder Pfad unter
//experimental/<actor>/*umgeht dieOWNERS-Prüfungen, damit Ingenieure und Agenten frei mitgit ws-exp <actor> <project>prototypisieren und das Paket später mitgit ws-graduatein eine Produktionsdomäne überführen können.
Code Review ohne Reibung: ephemere PRs und Snapshot-Diffs
Da refs/heads/main nur die Control Plane enthält und refs/trunk/main ein Commit ohne Eltern ist, würde ein direkt aus einem Workspace-Branch nach main geöffneter Standard-GitHub-Pull-Request versuchen, unverbundene Historien zu vergleichen. Wir haben das mit drei Review-Workflows gelöst, die auf unterschiedliche Änderungen zugeschnitten sind:
- Sofortige Zwei-Punkt-Diffs für Workspaces (
git ws-save+ Edge-Diff-Router) Das Pushen eines Workspaces mitgit ws-savemachtrefs/ws/<actor>/<id>über einen leichtgewichtigen Edge-Worker zugänglich. Dieser Worker löstrefs/trunk/mainund die Workspace-Referenz in ihre Commit-SHAs auf und leitet auf die Zwei-Punkt-Vergleichsansicht von GitHub weiter (/compare/<trunk-sha>..<ws-sha>). Bei kleinen Patches oder von Agenten erzeugten Änderungen können Reviewer den Diff prüfen und in der Weboberfläche direkt auf Land klicken. - Ephemere GitHub-Pull-Requests (
git ws-pr) Für zeilenweises Review auf GitHub pushtgit ws-prden Root-Snapshot-Commit ($(git rev-list --max-parents=0 HEAD)) nachrefs/heads/base/<id>und die Workspace-Spitze nachrefs/heads/review/<id>. Anschließend öffnet es einen GitHub-Pull-Request, derreview/<id>mitbase/<id>vergleicht. Da der Basis-Branch der Snapshot ist, von dem der Workspace abgezweigt wurde, zeigt der Tab Files changed von GitHub nur das Workspace-Delta an. Klickt der Reviewer auf Merge pull request, befördert ein Webhook den Head-Commit nachrefs/heads/land/<id>, führt die Landing-Pipeline im Speicher aus und löscht automatisch sowohlrefs/heads/base/<id>als auchrefs/heads/review/<id>. - Pull Requests auf externe Spiegel Open-Source-Mitwirkende müssen den Monorepo-Workflow nie erlernen. Sie forken die eigenständigen Spiegel-Repositories und öffnen dort wie gewohnt Pull Requests.
Änderungen, Patchsets und Übertragung von Genehmigungen
Ein Branch-Name kann eine Änderung nicht eindeutig identifizieren. Ein Agent kann seinen Branch umbenennen, die Spitze korrigieren oder vor dem Landen mehrfach auf einen neueren Trunk rebasen. Wie bei Gerrit identifiziert der Workflow eine Änderung über einen Trailer Change-Id: I<40 Hex-Zeichen> in der Commit-Nachricht der Spitze. git ws-save, git ws-pr und git ws-land ergänzen den Trailer, wenn die Spitze keinen besitzt, und behalten ihn andernfalls bei, sodass die ID Amends, Rebases und Umbenennungen übersteht. Der gelandete Trunk-Commit behält den Trailer und vermerkt die Nummer seines Review-Pull-Requests, sodass git trunk-cl <number|Change-Id> ihn in refs/trunk/history findet.
Jede zum Review eingereichte Spitze wird zu einem Patchset. git ws-pr schiebt sie in die unveränderliche Referenz refs/ws/cl/<change-id>/<tip> neben den Review-Branches. Erneutes Ausführen von git ws-pr nach einem Amend oder einem git ws-sync fügt dem selben Pull Request ein Patchset hinzu. git ws-ps listet die Patchsets der aktuellen Änderung auf, und git ws-psdiff <a> <b> gibt das Interdiff zwischen zwei von ihnen aus, sodass ein Reviewer nur das liest, was sich seit der letzten Runde verändert hat.
GitHub bindet eine Genehmigung an einen einzelnen Commit, weshalb jeder Rebase normalerweise ein neues Review erfordern würde. Die Landing-Pipeline akzeptiert außerdem eine Genehmigung, die einem anderen Patchset derselben Änderung erteilt wurde, sofern beide Patchsets auf ihrem jeweiligen Basis-Snapshot denselben Patch anwenden. Dazu vergleicht sie git patch-id --verbatim über den vollständigen binären Diff. Ein sauberer Rebase auf einen neueren Trunk landet ohne erneutes Review, während jede inhaltliche Änderung, einschließlich einer Änderung von Leerzeichen oder Dateimodus, eine neue Genehmigung erfordert.
Bidirektionale Synchronisation mit O(Delta) und getrennte Produktionsbranches
Viele Organisationen veröffentlichen einzelne Pakete als eigenständige GitHub-Repositories, damit externe Nutzer go get oder cargo install ausführen oder ein einzelnes Projekt forken können, ohne das Monorepo zu berühren. Manche Projekte, etwa statische Blogs oder freigabegesteuerte Web-Apps, pflegen zudem einen eigenen Branch production neben main.
Unsere Starlark-Synchronisationsengine behandelt sowohl ausgehende Exporte als auch eingehende Beiträge in O(Delta)-Zeit, die proportional zu den in einem Commit geänderten Dateien ist und nicht zur Größe des Monorepos:
- Blobless-Index-Splicing: Beim Einfügen oder Herauslösen eines Teilbaums eines Spiegel-Repositories in den bzw. aus dem Root-Tree des Monorepos setzt die Engine
GIT_NO_LAZY_FETCH=1und führtgit update-index --index-infogefolgt vongit write-tree --missing-okaus. Unveränderte Teilbäume undblobs bleiben über ihren SHA-1 referenziert und werden nie auf den CI-Runner heruntergeladen. - Prefetching nur der Deltas von Blobs: Bevor ein exportierter Commit in ein eigenständiges Spiegel-Repository gepusht wird, führt das Skript
git diff-tree -r --diff-filter=AM "$ext_parent" "$export_tree"aus und lädt übergit cat-file --batchnur die alten und neuenblobs der geänderten Dateien vor. Git kann dann ein schlankes Delta-Pack berechnen und in Sekunden an das Spiegel-Repository pushen. - Erhalt von Workflow- und Release-Branches: Beim ausgehenden Export bewahrt der Synchronisierer das eigene Verzeichnis
.github/workflows/jedes eigenständigen Repositories, sodass öffentliche CI-Runner die Projekttests auf dem Spiegel ausführen. Jeder Workflow in der Starlark-Konfiguration zielt auf einen expliziten Branch wiemain, wodurch Release-Gates für Repositories erhalten bleiben, die von einem separaten Branchproductionaus deployen. Landungen im Monorepo synchronisieren mit dem Branchmaindes Spiegels, und automatisierte Metadaten- oder Übersetzungs-Commits aufmainwerden per Webhook zurück nachrefs/trunk/mainsynchronisiert. Das Hochstufen vonmainnachproductionbleibt ein expliziter Freigabeschritt.
Schlussbemerkungen
Diese Architektur behandelt den Objektspeicher von Git als Content-Addressable Store, trennt refs/heads/main von refs/trunk/main und refs/trunk/history, identifiziert jede Änderung über eine Change-Id mit unveränderlichen Patchsets und führt Trees im Speicher mit git merge-tree --write-tree zusammen. Der Aufwand für das Onboarding wächst mit den Verzeichnissen, die eine Aufgabe benötigt, und der Aufwand für Landungen und die Spiegel-Synchronisation wächst mit der Größe einer Änderung, nicht mit der Größe des Repositories.