---
id: 773766eac9e6ff3c46bd686d78539aed
author: Lemon Mint
title: 'Prehodnotenie Git monorepo: CAS-native architektúra pre ľudí a kódovacích agentov'
description: Ako vybudovať monorepo bez démonov, natívne založené na CAS, na štandardnom Git-e, využívajúce parentless snapshoty kmeňa, izolované referencie pracovných priestorov, zlučovacie stromy v pamäti, hierarchické súbory OWNERS a synchronizáciu zrkadiel s časovou zložitosťou O(delta).
language: sk
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
---

Každá rastúca inžinierska organizácia si nakoniec musí vybrať medzi mnohými repozitármi a jedným. Keď začnete s desiatkami malých repozitárov, život je spočiatku jednoduchý. Každá knižnica má vlastný systém na sledovanie problémov, vlastnú CI pipeline a `git clone`, ktorý sa dokončí v priebehu sekúnd. Potom zmeníte štruktúru v jadrovom sieťovom balíku a zvyšok popoludnia strávite otváraním pull requestov na zvýšenie verzie v šiestich nadväzujúcich repozitároch, pričom čakáte, kým sa CI fronty vyprázdnia v topologickom poradí.

Ak všetko presuniete do tradičného Git monorepozitára, výmenou za koordináciu medzi repozitármi získate veľkosť repozitára ako problém. Keď sa história commitov prehlbuje a binárne assety sa hromadia v minulých revíziách, `git fetch` sa spomaľuje. Pracovné stromy narastú na gigabajty. Čoskoro niekto navrhne zriadiť vlastný virtuálny súborový démon, dedikovaný server na code review alebo flotilu vzdialených build workerov, len aby bol každodenný vývoj znesiteľný.

Keď sa do tímu pridajú autonómni agenti pre programovanie, obe zlyhania sa zhoršia. Polyrepozitáre zaslepia agenta voči volajúcim v iných projektoch a nútia ho žonglovať s prihlasovacími údajmi naprieč repozitármi. Tradičné monorepozitáre pri každej inicializácii úlohy zahltia disk kontajnera agenta a sieťovú šírku pásma, zatiaľ čo súbežní agenti pracujúci na tej istej vetve vytvárajú nekonečné rebase preteky.

Inšpirovaní architektúrou `google3` sme vytvorili jednokmeňové atomické zmeny, sub-sekundové riedke onboardovanie, hierarchickú správu `OWNERS` a samostatné open-source zrkadlá so štandardnými Git nástrojmi a bežným objektovým úložiskom.

Návrh nepotrebuje ani vlastný súborový démon, ani externú appliance na review, pretože s Gitom zaobchádza ako s Merkle-tree Content-Addressable Store (CAS).

## Mylná predstava v srdci pomalých Git monorepozitárov

Keď vývojári sťažujú, že Git sa neškáluje na veľké monorepozitáre, zriedkakedy narážajú na limit objektovej databázy Gitu. V `.git/objects` Git ukladá tri nemenné primitíva identifikované hashom ich obsahu SHA-1 (alebo SHA-256):

1. **`blob`**: Surový bajtový obsah jedného súboru.
2. **`tree`**: Výpis adresára, ktorý mapuje názvy súborov a oprávnenia na hashe `blob` alebo podradených `tree`.
3. **`commit`**: Malá textová hlavička (zvyčajne 200 až 300 bajtov), ktorá ukazuje na jeden koreňový hash `tree`, nula alebo viac rodičovských hashov `commit` a metadáta autora.

Ak monorepozitár obsahuje 50 000 súborov a upravíte jeden riadok v jednom súbore, nový commit znovu použije presné hashe `blob` a `tree` pre ostatných 49 999 súborov.

Tradičný Git monorepozitár pôsobí ťažkopádne, pretože konvencia preťažuje jednu referenciu, `refs/heads/main`, tromi navzájom si odporujúcimi úlohami:

- Drží **celý zjednotený adresárový strom** každého projektu.
- Ťahá so sebou **celý reťazec historických commitov naviazaných na rodičov** až do prvého dňa.
- Nachádza sa v `refs/heads/*`, mennom priestore, ktorý Git servery štandardne oznamujú a s ktorým sa dohadujú pri každom `git clone` a `git fetch`.

Zakaždým, keď vývojár alebo CI runner stiahne `refs/heads/main`, klient a server sa dohodnú na dosiahnuteľnosti v grafe commitov naprieč tisíckami historických revízií. Ak niekto pred tromi rokmi omylom commitol 100 MB archív a na druhý deň ho zmazal, jeho `blob` stále visí na historickom `tree`, ktorý je dosiahnuteľný z `refs/heads/main`.

## Oddelenie menného priestoru referencií

Git wire protokol počas štandardného klonovania oznamuje iba `refs/heads/*` a `refs/tags/*`. Referencie v používateľských menných priestoroch, napríklad `refs/trunk/*` alebo `refs/ws/*`, žijú v presne tom istom objektovom úložisku na serveri, profitujú z rovnakej delta kompresie v packfile a možno ich explicitne stiahnuť alebo odoslať, no nespôsobujú žiadnu réžiu pri predvolených klonoch.

Rozdelenie týchto úloh medzi samostatné referencie v jednom repozitári odstraňuje úzke miesto:

```
refs/heads/main               Iba riadiaca rovina (~20 KB: pravidlá, .gitconfig, konfigurácia synchronizácie, skripty)
refs/trunk/main               Snapshot commit bez rodiča ukazujúci na najnovší zjednotený koreňový strom
refs/trunk/history            Lineárny reťazec commitov naviazaných na rodičov, zdieľajúci presne koreňový strom SHA-1
refs/ws/<actor>/<id>          Izolované snapshoty pracovných priestorov (changelists) pre každého vývojára alebo agenta
refs/ws/cl/<change-id>/<tip>  Nemenné patchsety: každý vrchol zmeny odoslaný na review
refs/heads/land/<id>          Efemérny spúšťač merge queue, ihneď po zlúčení vymazaný
```

### 1. Riadiaca rovina (`refs/heads/main`)

Predvolená vetva neobsahuje žiadny zdrojový kód aplikácie. Sleduje iba pravidlá prevádzky repozitára (`AGENTS.md`, `README.md`), zdieľaný `.gitconfig` s aliasmi pracovných postupov, konfiguráciu synchronizácie v Starlarku (`sync.star`) a serverové skripty na zlučovanie. Klonovanie predvolenej vetvy prenesie približne 20 KB a dokončí sa v milisekundách.

### 2. Snapshot zjednoteného kmeňa bez rodiča (`refs/trunk/main`)

`refs/trunk/main` ukazuje na kompletný, zjednotený zdrojový strom celej organizácie (`//web/*`, `//net/*`, `//ipc/*`, `//storage/*`, `//crypto/*`, `//ai/*`, `//devtools/*`, `//corp/*`, `//third_party/*`, `//experimental/*`), ale jeho commit objekt vzniká **bez prepínača `-p` pre rodiča**.

Keďže `refs/trunk/main` nemá žiadnych rodičov (`parents = []`), jeho stiahnutie nevyžaduje žiadne dohadovanie o grafe commitov. Git server neprechádza históriu; pošle jediný hlavný commit a jeho aktuálne adresárové objekty `tree`. Historické binárne súbory alebo súbory zmazané pred mesiacom nie sú z `refs/trunk/main` dosiahnuteľné a nikdy sa neprenášajú.

### 3. Lineárna auditná história (`refs/trunk/history`)

Vývojári stále potrebujú `git blame` a `git log` pri vyšetrovaní regresií. Pri každom pristátí zmeny skript na zlučovanie vytvorí dva commit objekty, ktoré ukazujú na **presne rovnaký koreňový hash SHA-1 `$NEW_TREE`**:

```bash
# Snapshot commit bez rodiča pre okamžité checkouty pracovného priestoru s hĺbkou 1
SNAP=$(git commit-tree "$NEW_TREE" -m "$RAW_MSG")

# Commit naviazaný na rodiča pre lineárny git log a 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"
```

Uchovanie `refs/trunk/main` aj `refs/trunk/history` neznásobuje nároky na úložisko. Keďže oba commity odkazujú na identický `$NEW_TREE` hash, Git's content-addressable store deduplikuje 100 % objektov `tree` a `blob`. Dodatočný náklad na snapshot bez rodiča predstavuje jediná hlavička commitu s veľkosťou 250 bajtov.

### 4. Izolované pracovné priestory (`refs/ws/<actor>/<id>`)

Vetvy s rozpracovanou prácou sa odosielajú do `refs/ws/<actor>/<id>`, nie do `refs/heads/*`. Sto agentov na programovanie môže ukladať checkpointy každú minútu bez zahlcovania rozbaľovacích zoznamov vetiev alebo spomaľovania `git fetch` pre ľudských inžinierov.

## Onboarding v štyroch krokoch: ako funguje riedky checkout s blobless klonovaním

S touto referenčnou štruktúrou nový vývojár alebo efemérny kontajner s agentom na programovanie neinštaluje vlastné CLI ani FUSE ovládač. Onboarding trvá štyri kroky so štandardným Gitom a aliasmi repozitára:

```bash
# 1. Klonovanie 20 KB riadiacej roviny s filtrovaním blobov a zapnutým riedkym režimom
git clone --filter=blob:none --sparse https://github.com/example-org/monorepo.git
cd monorepo

# 2. Načítanie aliasov repozitára a pripojenie refs/trunk/*
git config include.path ../.gitconfig
git trunk-init

# 3. Deklarovanie doménových adresárov potrebných pre túto úlohu
git sparse-checkout set net/relay ipc/codec

# 4. Vytvorenie izolovaného pracovného priestoru zakoreneného v najnovšom snapshote kmeňa
git ws-new alice/optimize-framing
```

Každý krok stiahne iba to, čo potrebuje:

1. `git clone --filter=blob:none --sparse` stiahne 20 KB riadiacej roviny z `refs/heads/main`.
2. `git trunk-init` nakonfiguruje `+refs/trunk/*:refs/remotes/origin/trunk/*` a spustí blobless fetch. Git stiahne metadáta `tree` pre `refs/trunk/main` (zvyčajne niekoľko desiatok kilobajtov) a **nula súborových blobov**.
3. `git sparse-checkout set net/relay ipc/codec` nariadi filtru indexu v cone režime Gitu, aby materializoval iba koreňový adresár a tieto dva podstromy.
4. `git ws-new` prepne na novú vetvu zakorenenú v `origin/trunk/main`. Git potom na požiadanie vyžiada iba objekty `blob` vnútri `net/relay` a `ipc/codec`. Zvyšných 95 % monorepozitára sa na disk nikdy nesťahuje.

### Budúci horizont: pripojenie `refs/trunk/main` ako virtuálneho súborového systému (VFS)

Riedky checkout s blobless klonmi pokrýva každodenné pracovné postupy bez dodatočných klientských nástrojov. Keďže `refs/trunk/main` je už čistý Merkle strom v Content-Addressable Store, architektúra zároveň poskytuje priamy základ pre voliteľný používateľský virtuálny súborový systém (VFS) cez FUSE na Linuxe, FileProvider na macOS alebo ProjFS na Windows:

1. **Okamžité pripojenie celého stromu**: Ľahký lokálny mount démon načíta koreňový objekt `tree` z `refs/trunk/main` a premietne celú hierarchiu adresárov monorepozitára do pracovného adresára v priebehu milisekúnd, čím odpadá potreba spúšťať `git sparse-checkout set`.
2. **Dopytovanie blobov na požiadanie**: Obsah súborov zostáva virtuálny, kým kompilátor, IDE alebo agent nevydá systémové volanie `open(2)` alebo `read(2)`. Démon potom stiahne zodpovedajúci `blob` SHA-1 z CAS endpointu a uloží ho do lokálneho NVMe úložiska.
3. **Copy-on-Write prekrytie pre pracovné priestory**: Lokálne úpravy sa zapisujú do ľahkej hornej prekrývacej vrstvy. Spustenie `git ws-save` zahashuje iba zmenené cesty v tomto prekrytí, zapíše aktualizované objekty `blob` a `tree` a odošle výsledný commit do `refs/ws/<actor>/<id>` bez prehľadávania nezmenených adresárov.

## Model changelistov na čistom Gite: zlučovanie na serveri v pamäti

V tradičnom Git pracovnom postupe zlúčenie feature vetvy buď vytvorí merge commit s dvoma rodičmi, čo robí históriu nelineárnou, alebo vyžaduje, aby vývojári manuálne robili rebase a súťažili so súbežnými pushmi do `main`.

Inšpirovaní modelom Changelist (CL) z `google3` predstavuje každý pracovný priestor v našej architektúre **jednu atomickú zmenu** voči snapshotu kmeňa. Počas lokálnej práce v `ws/alice/optimize-framing` môže vývojár alebo agent urobiť desať inkrementálnych commitov (`wip`, `fix tests`, `lint`). Keď je zmena pripravená na pristátie, server zbalí rozdiel pracovného priestoru do jedinej lineárnej revízie kmeňa bez toho, aby na CI runneri kedy vykonal checkout pracovného adresára.

Takto skript pristátia (`land.sh`) beží v pamäti pomocou nástrojov Git 2.40+:

```bash
# 1. Identifikácia koreňového snapshot commitu, z ktorého sa pracovný priestor odvetvil
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. Výpočet zlúčeného koreňového stromu v pamäti bez checkoutu pracovného stromu
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 "Zistený konflikt pri zlučovaní; spustite git ws-sync na rebase." >&2
  exit 1
fi
```

V kroku 2:

- Bez ohľadu na to, koľko lokálnych commitov vzniklo vo vetve pracovného priestoru, skript porovnáva iba tri hashe stromov: pôvodný základný snapshot (`$BASE_TREE`), aktuálny snapshot kmeňa (`$MAIN_TREE`) a výsledný strom pracovného priestoru (`$WORK_TREE`).
- Ak sa `refs/trunk/main` posunul v `//web/blog`, kým Alice upravovala `//net/relay`, `git merge-tree --write-tree` vypočíta kombinovaný koreňový strom `$NEW_TREE` priamo v objektovom úložisku Gitu v priebehu milisekúnd, bez zapisovania súborov na súborový systém runnera.
- Po úspešnom prejdení nižšie uvedených kontrol politík jeden `git push --atomic` s `--force-with-lease` aktualizuje `refs/trunk/main`, pripojí jeden lineárny commit do `refs/trunk/history` a spúšťacia referencia pristátia `refs/heads/land/<id>` sa vymaže.

## Vynucovanie hraníc architektúry: štvorúrovňová viditeľnosť a hierarchické `OWNERS`

Konsolidácia kódu do jedného repozitára funguje iba vtedy, ak sa hranice medzi doménami vynucujú mechanicky ešte pred tým, ako môže commit pristáť. Hneď po tom, ako `git merge-tree --write-tree` vytvorí `$NEW_TREE` (a pred tým, ako `git push --atomic` aktualizuje kmeň), náš policy engine spustí dve kontroly so zložitosťou O(delta) nad `git diff-tree "$MAIN_TREE" "$NEW_TREE"`.

### 1. Štvorúrovňová viditeľnosť domén

Koreňový strom je rozdelený do štyroch úrovní viditeľnosti:

| Prefix adresára                                                                        | Úroveň            | Povolené importy                                 | Zakázané importy               | Brána `OWNERS`        |
| :------------------------------------------------------------------------------------- | :---------------- | :----------------------------------------------- | :----------------------------- | :--------------------- |
| `//web/*`, `//net/*`, `//ipc/*`, `//storage/*`, `//crypto/*`, `//ai/*`, `//devtools/*` | Verejná produkcia | Verejná produkcia, `//third_party/*`             | `//corp/*`, `//experimental/*` | Vynucovaná             |
| `//third_party/*`                                                                      | Externý dodávateľ | Samostatné alebo `//third_party/*`               | Všetky domény okrem `third_party` | Vynucovaná          |
| `//corp/*`                                                                             | Interný súkromný  | Verejná produkcia, `//corp/*`, `//third_party/*` | `//experimental/*`             | Vynucovaná             |
| `//experimental/<actor>/*`                                                             | Pieskovisko       | Ľubovoľný balík okrem `corp`                     | `//corp/*`                     | Vynímaná (automaticky schválené) |

Ak sa verejný balík v `//web/*` pokúsi importovať interný balík z `//corp/*` alebo neabsolvovaný prototyp z `//experimental/*`, úloha pristátia sa preruší skôr, než sa dotkne `refs/trunk/main`.

### 2. Hierarchické overovanie `OWNERS` bez servera Gerrit

Verifikátor vynucuje súbory `OWNERS` na úrovni adresárov s pravidlami dedičnosti:

- Pre každú cestu zmenenú medzi `$MAIN_TREE` a `$NEW_TREE` verifikátor prechádza smerom nahor od adresára súboru k `//OWNERS`.
- Ľubovoľný súbor `OWNERS` môže deklarovať `set noparent`, čím zablokuje dedené schválenia z nadradených adresárov, alebo `per-file *.sql=@dba-team`, čím obmedzí schválenia podľa glob vzoru názvu súboru.
- **Invariant proti manipulácii**: Existujúce súbory `OWNERS` sa vždy čítajú z `$MAIN_TREE` (aktuálny strom kmeňa), nikdy z `$NEW_TREE`. Neschválený autor si nemôže udeliť oprávnenie úpravou `OWNERS` v tom istom commite pracovného priestoru.
- **Výnimka pre pieskovisko**: Každá cesta pod `//experimental/<actor>/*` obchádza kontroly `OWNERS`, aby inžinieri a agenti mohli voľne prototypovať pomocou `git ws-exp <actor> <project>` a neskôr balík povýšiť do produkčnej domény pomocou `git ws-graduate`.

## Review kódu bez trenia: efemérne PR a diffy snapshotov

Keďže `refs/heads/main` obsahuje iba riadiacu rovinu a `refs/trunk/main` je commit bez rodiča, otvorenie štandardného GitHub Pull Requestu priamo z vetvy pracovného priestoru do `main` by porovnávalo nesúvisiace históriu. Vyriešili sme to tromi review workflowmi prispôsobenými rôznym typom zmien:

1. **Okamžité dvojbodkové diffy pracovného priestoru (`git ws-save` + Edge Diff Router)**
   Odoslanie pracovného priestoru pomocou `git ws-save` sprístupní `refs/ws/<actor>/<id>` cez ľahký edge worker. Tento worker preloží `refs/trunk/main` a referenciu pracovného priestoru na SHA commitov a presmeruje na dvojbodkové porovnávacie zobrazenie GitHubu (`/compare/<trunk-sha>..<ws-sha>`). Pri malých záplatách alebo zmenách generovaných agentmi môžu recenzenti skontrolovať diff a kliknúť priamo vo webovom rozhraní na **Land**.
2. **Efemérne GitHub Pull Requesty (`git ws-pr`)**
   Pre riadkové review na GitHube `git ws-pr` odošle koreňový snapshot commit (`$(git rev-list --max-parents=0 HEAD)`) do `refs/heads/base/<id>` a vrchol pracovného priestoru do `refs/heads/review/<id>`. Potom otvorí GitHub Pull Request porovnávajúci `review/<id>` s `base/<id>`. Keďže základná vetva je snapshot, z ktorého sa pracovný priestor odvetvil, záložka **Files changed** na GitHube zobrazuje iba rozdiel pracovného priestoru. Keď recenzent kliknie na **Merge pull request**, webhook povýši hlavný commit na `refs/heads/land/<id>`, spustí zlučovací postup pristátia v pamäti a automaticky vymaže `refs/heads/base/<id>` aj `refs/heads/review/<id>`.
3. **Pull Requesty do externých zrkadiel**
   Prispievatelia z open-source komunity sa nikdy nemusia učiť pracovný postup monorepozitára. Vytvoria fork a otvoria pull requesty voči samostatným zrkadlovým repozitárom ako obvykle.

### Zmeny, patchsety a prenos schválení

Názov vetvy nemôže identifikovať zmenu. Agent môže premenovať svoju vetvu, upraviť vrchol alebo viackrát urobiť rebase na novší kmeň, kým zmenu zlúči. Podobne ako v Gerrite, pracovný postup identifikuje zmenu pomocou trailera `Change-Id: I<40 hex>` v správe vrcholového commitu. `git ws-save`, `git ws-pr` a `git ws-land` tento trailer pridajú, ak ho vrchol nemá, a inak ho ponechajú, takže identifikátor prežije amendy, rebase aj premenovania. Pristátý commit v kmeni si trailer zachová a zaznamená číslo svojho review pull requestu, takže ho `git trunk-cl <number|Change-Id>` nájde v `refs/trunk/history`.

Každý vrchol odoslaný na review sa stane patchsetom. `git ws-pr` ho odošle do nemennej referencie `refs/ws/cl/<change-id>/<tip>` vedľa review vetiev. Opätovné spustenie `git ws-pr` po amende alebo `git ws-sync` pridá patchset do toho istého pull requestu. `git ws-ps` vypíše patchsety aktuálnej zmeny a `git ws-psdiff <a> <b>` vypíše interdiff medzi dvoma z nich, takže recenzent číta iba to, čo sa zmenilo od posledného kola.

GitHub viaže schválenie na jeden commit, takže každý rebase by inak vyžadoval nové review. Pristávací postup preto akceptuje aj schválenie udelené inému patchsetu tej istej zmeny, ak oba patchsety robia rovnakú záplatu voči svojmu vlastnému základnému snapshotu. Porovnáva `git patch-id --verbatim` nad úplným binárnym diffom. Čistý rebase na novší kmeň pristane bez ďalšieho review, zatiaľ čo každá úprava obsahu vrátane zmeny whitespace alebo režimu súboru si vyžaduje nové schválenie.

## Obojsmerná synchronizácia O(delta) a oddelené produkčné vetvy

Mnohé organizácie publikujú jednotlivé balíky ako samostatné GitHub repozitáre, aby ich externí používatelia mohli použiť cez `go get` alebo `cargo install` či forknúť jeden projekt bez zásahu do monorepozitára. Niektoré projekty, napríklad statické blogy alebo webové aplikácie viazané na release, navyše udržiavajú vetvu `production` popri `main`.

Náš synchronizačný engine v Starlarku spracúva odchádzajúce exporty aj prichádzajúce príspevky v čase **O(delta)**, úmernom súborom zmeneným v commite, nie veľkosti monorepozitára:

- **Splicing indexu bez blobov**: Pri vkladaní alebo vyberaní podstromu zrkadlového repozitára do koreňového stromu monorepozitára engine nastaví `GIT_NO_LAZY_FETCH=1` a spustí `git update-index --index-info` a potom `git write-tree --missing-ok`. Nezmenené podstromy a bloby zostávajú referencované pomocou SHA-1 a nikdy sa nesťahujú na CI runner.
- **Predbežné sťahovanie blobov iba pre zmeny**: Pred odoslaním exportovaného commitu do samostatného zrkadla skript spustí `git diff-tree -r --diff-filter=AM "$ext_parent" "$export_tree"` a pomocou `git cat-file --batch` predbežne stiahne iba starý a nový blob zmenených súborov. Git potom môže vypočítať tenký delta pack a odoslať ho do zrkadlového repozitára v priebehu sekúnd.
- **Zachovanie workflowov a release vetiev**: Počas odchádzajúceho exportu synchronizátor zachováva vlastný adresár `.github/workflows/` každého samostatného repozitára, aby verejné CI runnery spúšťali testy projektu na zrkadle. Každý workflow v konfigurácii Starlarku cieli na explicitnú vetvu, napríklad `main`, čím sa zachovávajú release brány pre repozitáre, ktoré nasadzujú zo samostatnej vetvy `production`. Pristátia v monorepozitári sa synchronizujú s vetvou `main` zrkadla a automatizované commity metadát alebo prekladov na `main` sa cez webhook synchronizujú späť do `refs/trunk/main`. Povýšenie `main` na `production` zostáva explicitným krokom vydania.

## Záverečné myšlienky

Táto architektúra považuje objektové úložisko Gitu za Content-Addressable Store, oddeľuje `refs/heads/main` od `refs/trunk/main` a `refs/trunk/history`, identifikuje každú zmenu pomocou `Change-Id` s nemennými patchsetmi a zlučuje stromy v pamäti pomocou `git merge-tree --write-tree`. Náklady na onboarding rastú s adresármi, ktoré úloha potrebuje, a náklady na pristátie a synchronizáciu zrkadiel rastú s veľkosťou zmeny, nie s veľkosťou repozitára.
