A git worktree megosztja a hookjaidat – amit a párhuzamos branch-checkout valójában jelent

A git worktree gyors és helytakarékos módja a párhuzamos branch-munkának, de nem ad külön .git-et: a hookok, a config és a stash is közösek maradnak. Megnézzük, mit jelent ez a gyakorlatban – és mikor jobb helyette a git clone --shared.

Egyre több fejlesztő fut párhuzamosan több branch-en: az egyik terminálban a feature branch, a másikban egy sürgős hotfix, a harmadikban egy code review. Az elmúlt egy-két évben ehhez társult egy új szokás is – ha AI-alapú kódoló ügynököt (Claude Code, Cursor, Codex CLI) futtatunk, azok gyakran maguktól hoznak létre külön munkafákat, hogy egyszerre több feladaton dolgozhassanak anélkül, hogy összeakadnának egymással. A mögöttük álló git funkció neve git worktree, és 2015 júliusában, a Git 2.5-ben jelent meg. A gond csak az, hogy a neve alapján sokan azt hiszik, ez tényleg különálló munkaterületeket jelent – miközben a valóság ennél árnyaltabb.

Diagram: egy közös .git tár, amelyhez három worktree kapcsolódik, mindegyik saját HEAD-del, index-szel és munkakönyvtárral, de közös objects, refs, config és hooks résszel

Mit csinál valójában a worktree add

A git worktree add ../feature nem klónoz repót, és nem is csak egy branch-váltás. Létrehoz egy új munkakönyvtárat, amelynek gyökerében nem egy .git mappa van, hanem egy .git fájl, ami visszamutat a fő repó .git/worktrees/<id> alkönyvtárára. Ott kap saját HEAD, ORIG_HEAD és index fájlt minden worktree – ez a három dolog tehát tényleg elkülönített. Mindent mást viszont megosztanak.

Kipróbáltam lokálisan:

$ git worktree add -b feature ../feature
Preparing worktree (new branch 'feature')
HEAD is now at 578b6fd init

$ git worktree list
/tmp/repo     578b6fd [master]
/tmp/feature  578b6fd [feature]

$ git worktree add ../feature2 feature
fatal: 'feature' is already checked out at '/tmp/feature'

Ez az utolsó sor fontos: egy adott branch-et egyszerre csak egy worktree-ben lehet checkoutolni. Ez véd meg attól, hogy két munkakönyvtárban párhuzamosan módosítsd ugyanazt a branch-et és index-et – ha ez nem lenne így, a második git add/git commit csendben felülírná az elsőét.

Amit tényleg megosztanak egymással

A hivatalos dokumentáció szerint minden worktree ugyanazt a refs/ névteret látja (a refs/bisect, refs/worktree és refs/rewritten kivételével), ugyanazt a .git/config-ot, és ugyanazt a .git/hooks mappát. Ez utóbbi különösen könnyen okoz meglepetést, mert nincs semmi a parancsban, ami erre figyelmeztetne.

Két gyors teszt ugyanabban a repóban, csak más worktree-ből:

$ cd feature
$ git config user.email "[email protected]"

$ cd ../repo
$ git config user.email
[email protected]   # a fő worktree konfigja is megváltozott
# a fő repóban elhelyezett hook...
$ echo 'echo INJECTED-HOOK-RAN >> /tmp/hook.log' > repo/.git/hooks/pre-commit
$ chmod +x repo/.git/hooks/pre-commit

# ...lefut, ha a MÁSIK worktree-ben commitolsz
$ cd feature && git commit -m test
$ cat /tmp/hook.log
INJECTED-HOOK-RAN

Tehát: a user.email beállítása, egy pre-commit hook elhelyezése vagy a stash (refs/stash is közös névtér) mind átnyúlik a worktree-határon. Ha csak a saját, egyszemélyes fejlesztői gépeden dolgozol két branch-csel párhuzamosan, ez inkább praktikus, mint veszélyes – az azonos konfiguráció és a közös object store pontosan az, amiért a worktree gyorsabb és kevesebb helyet foglal, mint egy teljes klón. A hivatalos doksi is felsorolja a extensions.worktreeConfig kapcsolót, amivel worktree-specifikus configot (core.sparseCheckout, core.bare stb.) lehet beállítani – de ez opt-in, alapból nincs bekapcsolva.

Miért lett ez most hirtelen fontos

A worktree tíz évig egy viszonylag ritkán használt, „power user” funkció volt. Az AI-kódoló ügynökök elterjedésével kapott új jelentőséget: ha egyszerre több ügynököt futtatsz ugyanazon a repón, a worktree tűnik a legkézenfekvőbb módnak arra, hogy mindegyik saját munkakönyvtárban dolgozzon, mégis gyorsan megosszák egymással a commit historyt. Csak épp az ügynökök – éppúgy, mint bármelyik shell parancs – ugyanazokkal a jogokkal férnek hozzá a közös .git tárhoz, mint te.

Ez nem elméleti probléma. A Claude Code issue trackerén a #72714-es és a #66993-as jegy is olyan esetet dokumentál, amikor a worktree létrehozása során a core.hooksPath beállítás véletlenül a fő repó megosztott configjába íródott, ezzel csendben kikapcsolva a globális git hookokat az egész klónban – nem csak az új worktree-ben. A Fletch csapatának összehasonlító mérése ugyanerre a következtetésre jut más irányból: a git/git repón tesztelve (318 MB .git, ~82 ezer commit) egy worktree létrehozása 826 ms-ig tartott és 58,7 MB helyet foglalt, egy git clone --shared pedig 870 ms-ig és 58,9 MB-ot – vagyis a sebesség- és helyelőny gyakorlatilag eltűnik, ha a klónozásnál a --shared kapcsolót használod, miközben az így kapott klón saját, elkülönített configot, hookokat és stash-t kap.

Mikor melyiket használd

  • Saját, egyszemélyes párhuzamos munka (hotfix közben feature branch, vagy egy PR gyors kipróbálása): worktree, mert kevesebb hely és gyorsabb setup, és te magad vagy az egyetlen „szereplő” a configban.
  • Több automatizált ügynök vagy CI job ugyanazon a repón, amikor nem akarod, hogy egyik felülírja a másik configját, stash-ét vagy hookját: inkább git clone --shared (vagy hardlinkes klón), mert az tényleg elkülönített .git-et ad, alig nagyobb költségért.
  • Submodule-okat használó repó: itt óvatosabban – a hivatalos dokumentáció szerint a submodule-ok támogatása worktree-kben még ma is nem teljes, és nem ajánlott több worktree-t nyitni egy submodule-okat tartalmazó szuperprojektből.

A gyakorlati tanulság egyszerű: a worktree remek eszköz arra, hogy egy fejlesztő gyorsan váltson kontextust anélkül, hogy stash-elne vagy újratelepítené a node_modules-t minden branch-váltáskor – de nem egy biztonsági határ, és nem is egy második, tőled elszigetelt repó. Ha ilyet szeretnél, a klónozás (lehetőleg --shared-del a helytakarékosság miatt) az, ami tényleg azt csinálja.

Források

Leave a Reply

Az e-mail címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük