Přeskočit na obsah

Tato stránka byla automaticky přeložena z angličtiny, jediného jazyka, ve kterém se tento web píše. Číst originál.

Topologie větev–worktree se odvozuje z identity gitu a vynucuje se všude

Topologie větev–worktree se odvozuje z identity gitu a vynucuje se všude

majordomus://adr/adr-0021přijato gitworktreesouborový systémagentikoordinace

odkazuje na

odkazuje na něj

21. Topologie větev–worktree se odvozuje z identity gitu a vynucuje se všude

Kontext

Na tomto repozitáři pracuje několik relací najednou — lidé i agenti, často čtyři nebo pět souběžně — a každá potřebuje vlastní checkout vlastní větve. Odpovědí gitu je linked worktree a git bere cíl jako argument: nemá žádný názor na to, kde má worktree žít, takže ho má každý volající.

V den, kdy bylo toto rozhodnutí učiněno, měl repozitář padesát tři registrovaných worktree ve čtyřech tvarech: třicet dva plochých sourozenců pojmenovaných prismatic-majordomus-<tag>, kde tag (cap, i1003, wtm) o větvi nic neříkal, šestnáct pod scratch adresáři relací v systémovém dočasném adresáři, jeden uvnitř primárního checkoutu pod .claude/worktrees/ a jeden zabírající prismatic-majordomus-wt — jediné jméno, které by chtěl kontejner. Jedenáct z nich drželo necommitnutou práci. Žádný člověk ani agent nedokázal odpovědět „kde je větev X checkoutnuta“ bez spuštění git worktree list a čtení, ani „kam patří nová“ bez vymýšlení odpovědi; a agent, kterému bylo řečeno „pracuj na feature/improve-cli“, zvolil věrohodný adresář, hodinu pracoval a nechal práci tam, kde ji další relace nebude hledat.

Dřívější pokus o toto rozhodnutí (větev feature/worktree-management) vložil do politiky sekci worktree: — strategii, příponu, pravidlo pojmenování, které zploštilo feature/foo do feature-foo — a druhý pokus by přidal registr mapující větve na cesty. Oba přidávají věc, kterou je třeba udržovat ve shodě s gitem.

Rozhodnutí

Topologie je funkcí identity gitu a názvu branche, každým povrchem počítaná stejně a nikde neuložená:

container(repository)        = parent(primary checkout) / basename(primary checkout) + "-wt"
worktree(repository, branch) = container(repository) / <branch name, one directory per component>

~/dev/prismatic-majordomus a feature/providers/openai-streaming proto dávají ~/dev/prismatic-majordomus-wt/feature/providers/openai-streaming. Hierarchie se zachovává; nic se neslučuje, nehashuje ani nečísluje. Primární checkout hostí trunk, který se zjišťuje (HEAD vzdáleného repozitáře, pak init.defaultBranch, pak jediné konvenční jméno, pak větev primárního checkoutu) a nikdy se nezadává pevně. Každá větev mimo trunk, která je checkoutnutá, má právě jeden worktree na této cestě.

Git je registr. Identita pochází ze společného git adresáře a hlavní worktree, který git worktree list --porcelain vypisuje první, takže odpověď je stejná z primárního checkoutu i ze čtyř adresářů hluboko v linkovaném worktree; worktree pocházejí z onoho seznamu; větve, jejich upstreamy a worktree z jednoho for-each-ref. Rust executable je interpretuje do jedné typované RepositoryTopology — každý worktree se statusem (primary, canonical, misplaced, detached, ephemeral, missing), každá větev s worktree nebo bez, každá diagnostika pod stabilním kódem s nápravou — a každý povrch tuto hodnotu vykresluje: příkazový řádek (majordomus worktree), čtyři schopnosti worktree.* (nástroje MCP a zdroj majordomus://worktrees, /api/v1/worktrees*, OpenAPI, Swagger UI), stránka Cockpitu, pre-commit ochrana a generovaný referenční přehled. Žádný soubor, sekce, tabulka ani seznam nezaznamenává cestu větve a přidání větve nevyžaduje upravit nic.

Starší topologie je vstupem migrace, nikdy druhou kanonickou formou. Worktree někde jinde je diagnostika (worktree.path_mismatch) a majordomus worktree migrate ho přivede domů pomocí git worktree move, včetně necommitnuté a nesledované práce, pod jedním zámkem v rozsahu repozitáře, s otiskem — větev, HEAD, index, staged a unstaged diffy, nesledované soubory s obsahem, ignorované položky přítomností — pořízeným před každým přesunem a po něm a porovnaným; krok se hlásí jako přesunutý, jen když se oba rovnají. Worktree zabírající cestu kontejneru se přesune ven a pak dovnitř; přesun mezi souborovými systémy se provede kopií, git worktree repair, ověřením proti manifestu každé položky stromu a teprve potom odstraněním originálu, a to jen na požádání. Nikdy se nic neresetuje, nestashuje, nečistí, neodchází na jiný checkout ani nemaže kvůli splnění pravidla.

Vynucování je vrstvené a poctivé. Doktrína a pravidlo projektu ho uvádějí; bootstrapy providerů to říkají každému agentovi; majordomus worktree create je způsob, jak vzniká worktree větve; pre-commit hook se ptá majordomus worktree guard, který odmítne commit feature větve odkudkoli jinde než z jejího kanonického worktree a commit primárního checkoutu mimo trunk; topologie je na každém povrchu, takže špatná je vidět; sada crate dokazuje odvození, bezpečnost a migraci proti skutečnému gitu; a kontrola CI drží části pohromadě. Git hooky lze obejít přes --no-verify a worker CI nevidí lokální souborový systém přispěvatele: toto rozhodnutí netvrdí opak. Tvrdí, že uvnitř workflowů řízených Majordomem je odchýlení od kanonické cesty odmítnuto a mimo ně je bolestivě viditelné.

Zvažované alternativy

Sekce politiky worktree: (strategie, přípona, pojmenování). Konfigurace pro fakt, který má jedinou správnou odpověď. Každý přepínač je způsob, jak dva checkouty jednoho repozitáře odvodí dva kontejnery, a pravidlo pojmenování, které zploštilo feature/foo na feature-foo, bylo záměrně ztrátové, což znamenalo kolize k detekci a mapování k vysvětlování.

Registrační soubor mapující větve na cesty. To, čím git už je, zapsané podruhé a zaručeně s ním do týdne nesouhlasící. Zamítnuto rovnou.

.worktrees/ uvnitř repozitáře. Checkout branche B uvnitř checkoutu branche A: každý nástroj buildu, watcher, linter a hledání do něj vstoupí, git musí dostat pokyn jej ignorovat a rm -rf repozitáře si necommitovanou práci B odnese s sebou.

~/.worktrees/<repo>/ nebo jiný globální adresář. Místo k vyhledávání, nikoli k odvozování, které přežije repozitáře, jež indexuje, a koliduje na základních názvech.

Dočasné adresáře vázané na relaci. Co se dělo. Pohodlné pro agenta a pro všechny ostatní neviditelné; šestnáct z padesáti tří bylo přesně tohle a nyní mají stav ephemeral: hlásí se, odmítají se pro commity, nikdy se nemigrují bez vyžádání a zmizí, když zmizí relace, která je vytvořila.

Ploché sourozenecké adresáře se značkou. Druhá věc, která se dělala; bylo jich dvaatřicet a každý vyžadoval, aby si člověk pamatoval, co i1011 bylo.

Důsledky

-wt se píše jednou, jako konstanta v crate v Rustu, a odvození žije v jednom modulu; vše ostatní — každá cesta v každé zprávě, stránce a dokumentu — z toho vyplývá. Bootstrapy poskytovatelů, dokumentace a kontrola CI příponu také jmenují a kontrola je drží u konstanty.

Primární checkout musí zůstat na trunku. Commit do feature větve z primárního checkoutu je odmítnut, což je změna zvyku pro každého, kdo tam používal git switch -c; náprava je jeden příkaz.

Topologie se odpovídá z gitu při každém volání a nikdy se necachuje mezi voláními: mění se mimo proces a cachovaná odpověď by byla odpovědí o repozitáři, který už neexistuje. To stojí několik podprocesů na volání a jeden git status na worktree, když se ptá na necommitnutou práci; guard na cestě commitu spustí jeden status, nikdy jeden na worktree.

Odpojené (detached) worktree nemají kanonickou cestu a nikdy se nepřesouvají; pracovní checkout relace (pod dočasným adresářem nebo .claude/worktrees/) se hlásí a ponechává relaci, která ho vytvořila. Holé (bare) repozitáře se odmítají jménem: topologie je definována proti primárnímu checkoutu.

Vytvoření je jeden příkaz a odstranění není práce nikoho, a ta asymetrie má svou cenu. Rozhodnutí nechává úklid jako odvozený stav — worktree cleanup jmenuje, co je zmergované a čisté, a nic nemaže — takže worktree přežije větev, která ho ospravedlňovala, dokud si na to někdo nevzpomene. Změřeno v tomto repozitáři 2026-09-08, osmnáct hodin po přistání topologie: šest worktrees drželo 78 GB v adresářích Rust target/ a dalších devět, jejichž větve už byly plně zmergované do trunku, drželo 26 GB. Svazek dosáhl 124 MiB volných z 926 GiB a selhání se neprojevilo jako selhání disku. Tři subsystémy místo toho hlásily chyby obsahu — pravidla, která se nevyřeší, scénář případu užití, který selže s detailem zapsaným do souboru, který se nedal zapsat, derive, který uspěje, a kontrola, která poté prohlásí jeho výstup za zastaralý — a několik relací strávilo hodiny tím, že je četlo jako souběh, tlak na paměť a nestabilní kontroly.

To je cena volby, nikoli argument proti ní: nástroj, který by smazal worktree proto, že jeho branch byla sloučena, by nakonec smazal práci, kterou někdo nedokončil, což je selhání, které celý tento návrh odmítá. Ale důsledek by měl být zapsán, nikoli objeven. Nic v topologii nic nezískává zpět, pro kontejner není deklarován žádný rozpočet a jediné, co říká stop, je disk — ve slovníku, který patří tomu subsystému, který zrovna píše jako další.

Tento repozitář rozhodnutí použil na sobě v den, kdy padlo: třicet dva sourozeneckých worktrees, z nichž jedenáct bylo špinavých, bylo spustitelným souborem přesunuto za méně než deset sekund se shodným otiskem každého; výjimkou bylo šestnáct pomíjivých pracovních checkoutů, worktree agenta uvnitř primárního checkoutu a jeden checkout mimo všechny konvence, který byl ponechán operátorovi.

Odkud to pochází

kanonický soubor
.ai/repo/adrs/0021-the-branch-to-worktree-topology-is-derived-from-git-identity-and-enfor.md
identity
adr-0021
dostupné také jako
Zdroj MCP majordomus://adr/adr-0021 · majordomus entity show adr/adr-0021 · GET /api/v1/entity?uri=majordomus://adr/adr-0021
v Cockpitu
/cockpit/objects/adr/adr-0021

Tato stránka je generována z výše uvedeného souboru pomocí scripts/generate-site-data; úprava stránky nic nemění, úprava souboru změní všechna rozhraní. Výše uvedené vztahy jsou hrany docs/generated/graph.json, které spustitelný program zapisuje ze stejného indexu.

Prohledává názvy a popisy všech stránek, které tento web publikuje.