---
id: 773766eac9e6ff3c46bd686d78539aed
author: Lemon Mint
title: 'Die Git-Monorepo neu denken: Eine CAS-native Architektur für Menschen und Coding-Agenten'
description: Wie man ein daemon-freies, CAS-natives Monorepo auf Standard-Git aufbaut, unter Verwendung von parentless Trunk-Snapshots, isolierten Workspace-References, In-Memory-Merge-Trees, hierarchischen OWNERS-Dateien und O(delta)-Mirror-Synchronisation.
language: de
date: 2026-10-30T01:17:15.292299Z
path: /blog/posts/rethinking-the-git-monorepo-a-cas-native-architecture-for-humans-and-coding-agents-zfd3d7931
category: lowlevel
---

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:

1. **`blob`**: Die rohen Bytes einer einzelnen Datei.
2. **`tree`**: Eine Verzeichnisliste, die Dateinamen und Berechtigungen auf `blob`- oder untergeordnete `tree`-Hashes abbildet.
3. **`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 jedem `git clone` und `git fetch` ankü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:

```
refs/heads/main               Nur Control Plane (~20 KB: Regeln, .gitconfig, Sync-Konfiguration, Skripte)
refs/trunk/main               Commit-Snapshot ohne Parent, der auf den neuesten einheitlichen Root-Tree zeigt
refs/trunk/history            Lineare Commit-Kette mit Parent-Verknüpfung, die exakt denselben Root-Tree-SHA-1 teilt
refs/ws/<actor>/<id>          Isolierte Workspace-Snapshots (Changelists) pro Entwickler oder Agent
refs/ws/cl/<change-id>/<tip>  Unveränderliche Patchsets: jeder Tip einer Änderung, der zum Review eingereicht wurde
refs/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:

```bash
# Commit-Snapshot ohne Parent für sofortige Workspace-Checkouts der Tiefe 1
SNAP=$(git commit-tree "$NEW_TREE" -m "$RAW_MSG")

# Commit mit Parent-Verknüpfung für lineares git log und git blame
HIST=$(git commit-tree "$NEW_TREE" -p "$OLD_HIST" -m "$RAW_MSG")

git push --atomic origin \
  --force-with-lease="refs/trunk/main:${OLD_MAIN}" \
  --force-with-lease="refs/trunk/history:${OLD_HIST}" \
  "${SNAP}:refs/trunk/main" \
  "${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:

```bash
# 1. Die 20 KB große Control Plane mit aktiviertem Blob-Filter und Sparse-Modus klonen
git clone --filter=blob:none --sparse https://github.com/example-org/monorepo.git
cd monorepo

# 2. Repository-Aliase laden und refs/trunk/* anbinden
git config include.path ../.gitconfig
git trunk-init

# 3. Die für diese Aufgabe benötigten Domänenverzeichnisse deklarieren
git sparse-checkout set net/relay ipc/codec

# 4. Einen isolierten Workspace anlegen, der auf dem neuesten Trunk-Snapshot basiert
git ws-new alice/optimize-framing
```

Jeder Schritt lädt nur das, was er benötigt:

1. `git clone --filter=blob:none --sparse` lädt die 20 KB große Control Plane auf `refs/heads/main` herunter.
2. `git trunk-init` konfiguriert `+refs/trunk/*:refs/remotes/origin/trunk/*` und führt einen Blobless-Fetch aus. Git lädt die `tree`-Metadaten für `refs/trunk/main` (typischerweise einige Dutzend Kilobyte) und **keine einzige Datei-`blob`**.
3. `git sparse-checkout set net/relay ipc/codec` weist den Cone-Mode-Index-Filter von Git an, nur das Root-Verzeichnis und diese beiden Teilbäume zu materialisieren.
4. `git ws-new` wechselt zu einem neuen Branch, der auf `origin/trunk/main` basiert. Git fordert anschließend nur bei Bedarf die `blob`-Objekte innerhalb von `net/relay` und `ipc/codec` an. 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:

1. **Sofortiges Einbinden des vollständigen Baums**: Ein leichtgewichtiger lokaler Mount-Daemon liest das Root-`tree`-Objekt von `refs/trunk/main` und projiziert die gesamte Verzeichnishierarchie des Monorepos innerhalb von Millisekunden in das Arbeitsverzeichnis. Ein Aufruf von `git sparse-checkout set` entfällt damit.
2. **Bedarfsgesteuertes Nachladen von Blobs**: Dateiinhalte bleiben virtuell, bis ein Compiler, eine IDE oder ein Agent einen Systemaufruf `open(2)` oder `read(2)` ausführt. Der Daemon lädt dann den entsprechenden SHA-1-`blob` vom CAS-Endpunkt und legt ihn auf lokalem NVMe-Speicher zwischen.
3. **Copy-on-Write-Overlay für Workspaces**: Lokale Änderungen werden in eine leichtgewichtige obere Overlay-Schicht geschrieben. Der Aufruf von `git ws-save` hasht nur die veränderten Pfade in diesem Overlay, schreibt die aktualisierten `blob`- und `tree`-Objekte und pusht den resultierenden Commit nach `refs/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:

```bash
# 1. Den Root-Snapshot-Commit ermitteln, von dem der Workspace abgezweigt wurde
BASE=$(git rev-list --max-parents=0 "$WORK_SHA")

BASE_TREE=$(git rev-parse "${BASE}^{tree}")
MAIN_TREE=$(git rev-parse "${OLD_MAIN}^{tree}")
WORK_TREE=$(git rev-parse "${WORK_SHA}^{tree}")

# 2. Den zusammengeführten Root-Tree im Speicher berechnen, ohne Working-Tree-Checkout
if [ "$MAIN_TREE" = "$BASE_TREE" ]; then
  NEW_TREE="$WORK_TREE"
elif OUT=$(git merge-tree --write-tree --merge-base="$BASE_TREE" "$MAIN_TREE" "$WORK_TREE"); then
  NEW_TREE=$(head -n1 <<<"$OUT")
else
  echo "Merge conflict detected; run git ws-sync to rebase." >&2
  exit 1
fi
```

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/main` in `//web/blog` vorangeschritten ist, während Alice `//net/relay` bearbeitet hat, berechnet `git merge-tree --write-tree` den kombinierten Root-Tree `$NEW_TREE` direkt 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 --atomic` mit `--force-with-lease` die Referenz `refs/trunk/main`, hängt einen linearen Commit an `refs/trunk/history` an, und der Landing-Trigger `refs/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_TREE` und `$NEW_TREE` geändert wurde, durchläuft der Verifizierer das Verzeichnis der Datei aufwärts bis `//OWNERS`.
- Jede `OWNERS`-Datei kann mit `set noparent` vererbte Genehmigungen aus übergeordneten Verzeichnissen blockieren oder mit `per-file *.sql=@dba-team` Genehmigungen ü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 er `OWNERS` im selben Workspace-Commit bearbeitet.
- **Ausnahme für Sandboxes**: Jeder Pfad unter `//experimental/<actor>/*` umgeht die `OWNERS`-Prüfungen, damit Ingenieure und Agenten frei mit `git ws-exp <actor> <project>` prototypisieren und das Paket später mit `git ws-graduate` in 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:

1. **Sofortige Zwei-Punkt-Diffs für Workspaces (`git ws-save` + Edge-Diff-Router)**
   Das Pushen eines Workspaces mit `git ws-save` macht `refs/ws/<actor>/<id>` über einen leichtgewichtigen Edge-Worker zugänglich. Dieser Worker löst `refs/trunk/main` und 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.
2. **Ephemere GitHub-Pull-Requests (`git ws-pr`)**
   Für zeilenweises Review auf GitHub pusht `git ws-pr` den Root-Snapshot-Commit (`$(git rev-list --max-parents=0 HEAD)`) nach `refs/heads/base/<id>` und die Workspace-Spitze nach `refs/heads/review/<id>`. Anschließend öffnet es einen GitHub-Pull-Request, der `review/<id>` mit `base/<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 nach `refs/heads/land/<id>`, führt die Landing-Pipeline im Speicher aus und löscht automatisch sowohl `refs/heads/base/<id>` als auch `refs/heads/review/<id>`.
3. **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=1` und führt `git update-index --index-info` gefolgt von `git write-tree --missing-ok` aus. Unveränderte Teilbäume und `blob`s 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 über `git cat-file --batch` nur die alten und neuen `blob`s 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 wie `main`, wodurch Release-Gates für Repositories erhalten bleiben, die von einem separaten Branch `production` aus deployen. Landungen im Monorepo synchronisieren mit dem Branch `main` des Spiegels, und automatisierte Metadaten- oder Übersetzungs-Commits auf `main` werden per Webhook zurück nach `refs/trunk/main` synchronisiert. Das Hochstufen von `main` nach `production` bleibt 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.
