270 lines
14 KiB
Markdown
270 lines
14 KiB
Markdown
# Git worktrees — praktická učebnice
|
|
|
|
*Zdroje: `git-scm.com/docs/git-worktree`, VS Code docs (branches-worktrees, 9/16/2026), Claude Code docs (worktrees). Vše ověřeno fetchem 2026-09-20.*
|
|
|
|
---
|
|
|
|
## 1. Co worktree je (mental model)
|
|
|
|
- Jedna repository (jeden `.git` adresář, jedna historie, branches, tags, remote) — **několik working directories**.
|
|
- **Primary worktree** = klasický checkout. **Linked worktree** = další adresář, který sdílí tu samou historii, ale má vlastní soubory, staging area a vlastní checked-out branch.
|
|
- Git **zakazuje mít jeden branch checkoutnutý ve dvou worktrees zároveň** — konflikt je vyloučen konstrukcí.
|
|
- Sdílené: historie, branches, tags, remotes, `.git/config`, stash.
|
|
- Nesdílené: soubory na disku, index, uncommitted changes.
|
|
- Nesrovnávat s clone: worktree nespotřebuje druhou kopii historie (hardlinked objects), nemá vlastní remote fetch, jeden `git fetch` platí pro všechny.
|
|
- Praktický důsledek: **gitignorované soubory se v novém worktree NEduplikují** — `.env`, `node_modules`, build outputy tam nejsou. Řešení viz níže.
|
|
|
|
---
|
|
|
|
## 2. CLI — kompletní kuchařka
|
|
|
|
### Základní lifecycle
|
|
|
|
```bash
|
|
# výpis
|
|
git worktree list
|
|
# /home/user/proj a1b2c3d [main] <- primary
|
|
# /home/user/proj-wt-fix e4f5g6h [fix/leak] <- linked
|
|
|
|
# nový worktree na nové branch (typicky hlavní užití)
|
|
git worktree add ../proj-fix -b fix/leak
|
|
|
|
# nový worktree na existující branch
|
|
git worktree add ../proj-main main # pozor: musí být volná (nesmí být checkoutnutá jinde)
|
|
|
|
# detachnutý (na konkrétním commitu, bez branch)
|
|
git worktree add ../proj-hotfix <commit-ish>
|
|
```
|
|
|
|
### Konvence umístění
|
|
|
|
Dvě osvědčené školy:
|
|
|
|
1. **Vedle repa** (`../proj-fix`, `../proj-auth`) — vhodné, když chceš každý worktree otevřít v jiné instanci editoru/IDE.
|
|
2. **Pod jedním rodičovským adresářem pro worktrees** (`../proj/.worktrees/` nebo `~/worktrees/proj/`), primární checkout zůstává čistý. Pozn.: Claude Code umísťuje své worktrees do `.claude/worktrees/<name>/` uvnitř repa.
|
|
3. (Pozor na `.gitignore` — worktree adresáře uvnitř repa musí být ignorované, jinak se Git snaží trackovat jejich obsah.)
|
|
|
|
### Denní provoz
|
|
|
|
```bash
|
|
cd ../proj-fix # pracuj úplně normálně
|
|
git status # funguje, vidí jen tenhle worktree
|
|
git add -A && git commit -m "fix"
|
|
git push -u origin fix/leak # sdílený remote, funguje
|
|
```
|
|
|
|
### Úklid
|
|
|
|
```bash
|
|
# bezpečné odstranění (odmítne, pokud jsou uncommitted změny)
|
|
git worktree remove ../proj-fix
|
|
|
|
# s násilím (zneužívej vědomě)
|
|
git worktree remove --force ../proj-fix
|
|
|
|
# worktree už je smazaný ručně (rm -rf) -> vyčistit admin metadata
|
|
git worktree prune
|
|
```
|
|
|
|
### Když to spadne (recovery)
|
|
|
|
- **Branch zůstala po remove viset** — branch nezávisí na worktree; smaž ji klasicky: `git branch -d fix/leak` (nebo `-D` pro nemergenutou).
|
|
- **`git worktree list` ukazuje mrtvé worktrees** → `git worktree prune` (git je nakonec pročistí sám dle `gc.worktreePruneExpire`, výchozí ~3 měsíce).
|
|
- **Nemůžeš checkoutnout branch** (`already checked out in ...`) → je checkoutnutá v jiném worktree: buď tam pokračuj, nebo tam dáš `git switch` jinam, nebo `git worktree add --force` (riskantní — stejná branch na dvou místech pak může divergovat).
|
|
- **Chceš zjistit, v čem je rozdíl oproti main** → vše funguje standardně: `git diff main...fix/leak`, `git log main..fix/leak`.
|
|
|
|
### LVM/Zabbix tipy pro homelab kontext
|
|
|
|
- worktrees sdílejí `.git` přes hardlinky → **dvě kopie velkého repa na disku netvoří** (přesto, `du -sh` počítá hardlinky dřív jen jednou — na velkých repos zkontroluj `du -sh --apparent-size`).
|
|
- `git gc` a `git worktree prune` v primary worktree spravují metadata všech linked worktrees.
|
|
- **Změna commitu v primary neovlivní soubory v linked worktree** — na testování dvou verzí side-by-side ideální.
|
|
|
|
### Vzorce pro denní použití
|
|
|
|
| Chci | Příkaz |
|
|
|---|---|
|
|
| Paralelně: hotfix do main + feature | `git worktree add ../proj-hotfix -b hotfix/prod-quirk` |
|
|
| Code review v čistém stavu | `git worktree add ../proj-review origin/pr-42` |
|
|
| Spustit starou verzi (demo/debug) | `git worktree add ../proj-v1.0 v1.0` |
|
|
| Bisect bez ztráty workspace | `git worktree add ../proj-bisect` (detached) |
|
|
|
|
---
|
|
|
|
## 3. VS Code — built-in podpora (ne extension)
|
|
|
|
VS Code má **nativní podporu worktrees** — Source Control view → Repositories → kontext menu repa → **Worktrees → Create Worktree**.
|
|
|
|
### Postup vytvoření
|
|
|
|
1. Otevři Source Control view (`Ctrl+Shift+G`).
|
|
2. Rozbal **Repositories** sekci (je-li skrytá, přes `...` menu view).
|
|
3. Reprodukovatelně: klikni na repozitář → `...` (More Actions) → **Worktrees → Create Worktree**.
|
|
4. Dialog: vyber branch + zadefinuj cestu (VS Code složku vytvoří a branch do ní checkoutne).
|
|
5. Nový worktree se objeví jako **samostatná položka v Repositories view**.
|
|
|
|
### Otevírání a switch
|
|
|
|
- Každý worktree otevřeš jako samostatnou složku = **samostatné VS Code okno** (doporučeno; každé okno má vlastní terminál, debug, problems).
|
|
- Cesty: `File → Open Recent` pro rychlý přístup; v Repositories view pravým na worktree → **Open Worktree in New Window / Current Window**; Command Palette: `Git: Open Worktree in New Window`.
|
|
- VS Code automaticky pozná, že otevřená složka je worktree (čte `.git` file → gitdir pointer).
|
|
|
|
### Nastavení, které se vyplatí
|
|
|
|
```jsonc
|
|
// settings.json
|
|
{
|
|
// kopírovat gitignorované soubory do nového worktree (glob patterns)
|
|
"git.worktreeIncludeFiles": [".env", "node_modules/**"],
|
|
|
|
// automaticky detekovat worktrees vytvořené mimo VS Code (např. z CLI)
|
|
"git.detectWorktrees": true,
|
|
"git.detectWorktreesLimit": 50 // default
|
|
}
|
|
```
|
|
|
|
- `git.worktreeIncludeFiles` — glob; soubor se zkopíruje **jen pokud matchne pattern A je gitignorovaný**. Typické: `.env`, `node_modules/**` (ušetří reinstall), `venv/**` pozor na absolutní cesty ve scripthích (activate skripty obsahují absolutní cesty — radši nový venv).
|
|
- `git.detectWorktrees` — pokud worktrees zakládáš z CLI, zapni; jinak VS Code vidí jen ty vytvořené přes GUI.
|
|
|
|
### Další GUI schopnosti
|
|
|
|
- **Compare with Workspace** — pravým na změněný soubor v worktree → diff oproti hlavnímu workspace, side-by-side.
|
|
- **Migrate Worktree Changes** (Command Palette) — zmerguje všechny změny z worktree do aktuálního workspace.
|
|
|
|
### Gotchas
|
|
|
|
- Multi-root workspace se všemi worktrees v jednom okně je technicky možný, ale search/Go-to-Definition ti bude míchat cesty — **preferuj jedno okno per worktree**.
|
|
- Search (`Ctrl+Shift+F`) jede na workspace složku, ne na repozitář — nečte automaticky worktrees mimo otevřenou složku.
|
|
- `git.worktreeIncludeFiles` neřeší `.env` typu "každý worktree jiný" — to je pořád ruční práce.
|
|
|
|
---
|
|
|
|
## 4. Claude Code — `--worktree` / `-w` (v2.1.49+)
|
|
|
|
### Založení izolované session
|
|
|
|
```bash
|
|
cd ~/src/repo
|
|
claude --worktree fix-leak # nebo -w fix-leak
|
|
# -> vytvoří .claude/worktrees/fix-leak/
|
|
# na branchi worktree-fix-leak (z remote default branch, typicky origin/main)
|
|
|
|
claude -w fix-leak -p "..." # non-interactive; -p přeskočí trust dialog
|
|
```
|
|
|
|
- Další terminál + jiné jméno = druhá paralelní session. Bez jména vygeneruje náhodné (typicky `bright-running-fox` styl).
|
|
- **Interactive mód vyžaduje workspace trust** — poprvé v adresáři spusť `claude` bez flagů a přijmi trust dialog, jinak `--worktree` spadne na erroru. `-p` (headless) trust check nedělá.
|
|
- Uvnitř session můžeš Claude říct "work in a worktree" → použije nástroj `EnterWorktree` (před vstupem do worktree mimo `.claude/worktrees/` se ptá na approval).
|
|
|
|
### Co je uvnitř a co chybí
|
|
|
|
- Worktree = **fresh checkout** (tracked soubory) — `.env`, `node_modules`, build cache ne. Řešení:
|
|
- nechat Claude nainstalovat závislosti v worktree,
|
|
- nebo přidat **`.worktreeinclude`** do rootu repa (syntaxe `.gitignore`; kopíruje jen soubory, které matchnou pattern **a** jsou gitignorované).
|
|
```gitignore
|
|
# .worktreeinclude
|
|
.env
|
|
.env.local
|
|
config/secrets.yaml
|
|
```
|
|
- Pozor na `**/` patterny u adresářů ignorovaných jako celek — radši pojmenuj adresář v patternu (`vendor/**/config.json` místo `**/config.json`).
|
|
|
|
### Cleanup a resume
|
|
|
|
- Při exitu interactive session Claude kontroluje worktree na změny: **čistý** → smaže worktree i branch (named session se předtím zeptá); **špinavý** (změny/untracked/commity) → prompt keep/remove. **Remove smaže i branch i veškerou práci v ní** — neodpovídej automatikou.
|
|
- `-p` (headless) cleanup nedělá — worktrees čistí až periodic sweep (dle `cleanupPeriodDays`) nebo ručně `git worktree remove`.
|
|
- `--continue` / `--resume` vrací session **zpět do jejího worktree**; `--fork-session` zůstává v launch adresáři. Deleted worktree → session se obnoví v launch adresáři.
|
|
- Resume z jiného worktree nebo z podadresáře worktree může selhat — **resumuj z main checkoutu**.
|
|
|
|
### Isolation enforcement (proč to je bezpečné)
|
|
|
|
Claude Code v izolované session blokuje:
|
|
1. **File edits** (`Edit`/`Write`/`NotebookEdit`) do main checkoutu.
|
|
2. **Commands s working directory v main checkoutu**.
|
|
3. **Git redirecty** (`git -C`, `--git-dir`, `GIT_DIR`/`GIT_WORK_TREE`, `cd` do main checkoutu).
|
|
4. **Nepřehledné commandy** (dynamicky sestavené git příkazy, které nelze staticky ověřit).
|
|
|
|
Platí pro session i všechny její subagenty, interaktivně i v backgroundu. **Vypnout se nedá.**
|
|
|
|
### Konfigurace
|
|
|
|
| Setting | Hodnota | Význam |
|
|
|---|---|---|
|
|
| `worktree.baseRef` | `"fresh"` (default) | Branch z remote default branch (typicky `origin/main`) |
|
|
| | `"head"` | Branch z aktuálního lokálního `HEAD` (in-progress práce) |
|
|
|
|
- Nelze zadat konkrétní branch jménem — na to je `git worktree add` ručně (viz Manage worktrees manually).
|
|
- **PR checkout**: `claude -w "#42"` nebo `claude -w "https://github.com/org/repo/pull/42"` (i GitLab MR URL). Worktree vznikne na `.claude/worktrees/pr-42`, branch z head commitu PR.
|
|
- Opětovné použití jména: existující adresář otevře místo vytvoření nového; za jistých podmínek (čistý, na své branchi, merged PR) resetuje na default branch, jinak pokračuje od starého tipu.
|
|
|
|
### Subagent isolation
|
|
|
|
- Řekni "use worktrees for your agents" → každý subagent dostane vlastní worktree.
|
|
- Trvale pro custom subagenta: frontmatter `isolation: worktree` v `.claude/agents/<name>.md`.
|
|
- Subagent worktree se automaticky odstraní, když subagent skončí bez změn; se změnami zůstává, dokud ho sweep (dle `cleanupPeriodDays`) nemůže bezpečně smazat.
|
|
- Během běhu agenta drží Claude Code na worktree `git worktree lock`, aby ho souběžný cleanup nesmazal.
|
|
|
|
### Sdílené prostředí s main checkoutem
|
|
|
|
- `.git` adresář (git commit z worktree funguje i se sandboxem), project-scope pluginy, uložené permission approvals (`settings.local.json`).
|
|
|
|
### Troubleshooting (nejčastější)
|
|
|
|
- **LFS / filter drivery**: `git lfs install --local` zapisuje filter do repo `.git/config` → v worktree jsou LFS pointer files místo obsahu. Fix: v worktree `git lfs pull`, preventivně používej globální `git lfs install` (bez `--local`).
|
|
- **Symlinky na `.claude`, `.claude/worktrees` nebo worktree path** → worktree creation odmítnut (bezpečnost).
|
|
- **`Refusing to use <path> as an isolation worktree`** → git metadata adresáře resolvovala do main checkoutu (typicky špatný `.git` pointer); řeš dle textu erroru.
|
|
- **`includeIf` v repo `.git/config`** blokuje tvorbu worktree — přesuň nastavení přímo do configu.
|
|
- **Network path worktree** (NFS/SMB) → nikdy se do něj nerresumuje.
|
|
|
|
---
|
|
|
|
## 5. Kombinace workflow: CLI + VS Code + Claude Code
|
|
|
|
Typický den s jedním repem `proj`:
|
|
|
|
```
|
|
~/src/proj # primary, main branch, VS Code okno A
|
|
~/src/proj-fix # linked worktree, fix/leak, VS Code okno B (vytvořeno GUI)
|
|
~/src/proj/.claude/worktrees/ # Claude Code sessions (feature-x, pr-42, ...)
|
|
```
|
|
|
|
```bash
|
|
# ráno: hotfix a feature paralelně
|
|
git -C ~/src/proj worktree add ../proj-fix -b fix/leak
|
|
code ../proj-fix # VS Code okno B
|
|
|
|
# feature paralelně přes Claude Code (jiný terminál)
|
|
claude -w feature-auth
|
|
|
|
# večer: úklid
|
|
git worktree remove ../proj-fix # po merge do main
|
|
claude # v interactive session exit -> cleanup prompt
|
|
```
|
|
|
|
### Rozdělení rolí
|
|
|
|
| Nástroj | Kdy |
|
|
|---|---|
|
|
| **CLI `git worktree`** | Plná kontrola (konkrétní branch, umístění mimo repo, bisect, srovnávání verzí) |
|
|
| **VS Code GUI** | Rychlé vytvoření/otevření, diff worktree vs. workspace (`Compare with Workspace`), `Migrate Worktree Changes` |
|
|
| **Claude Code `-w`** | Paralelní AI session bez rizika kolize editů; PR review (`-w "#42"`) |
|
|
|
|
### Pravidla, na která se vyplatí držet
|
|
|
|
1. **Jeden worktree = jeden úkol = jedna branch**. Nesdílej worktree mezi dvěma tasky.
|
|
2. **Merge řeš v primary checkoutu**, ne v worktree — tam jen commit a push.
|
|
3. **Po skončení tasku worktree odstraň** — worktrees se hromadí rychleji, než člověk čeká (`git worktree list` ať je pravidelný reflex).
|
|
4. **`.worktreeinclude` / `git.worktreeIncludeFiles` nastav hned u repa**, kde `.env`/deps potřebuješ — neaž při prvním kopnutí do stěny.
|
|
5. Venv/deps s absolutními cestami (venv, node_modules symlinkované) do worktree necopyuj — vytvoř nové.
|
|
6. **Claude Code worktree nemaž ručně, dokud session žije** — drží na něm lock; sweep/exit ho uklidí sám.
|
|
|
|
---
|
|
|
|
## 6. Cvičení (udělej na play repu)
|
|
|
|
1. `git init /tmp/wt-play && cd /tmp/wt-play && echo a > f && git add . && git commit -m init`
|
|
2. `git worktree add ../wt-play-fix -b fix/x` — uprav `f`, commit v worktree; `cd` zpět do primary — soubor se nezměnil (sdílená historie, ne soubory).
|
|
3. `git worktree list` — najdi oba.
|
|
4. Zkus checkoutnout `fix/x` v primary → git odmítne (already checked out). Správná cesta: pracuj v worktree.
|
|
5. `git worktree remove ../wt-play-fix && git branch -d fix/x`
|
|
6. VS Code: vytvoř worktree přes Source Control GUI, otevři v novém okně, vyzkoušej `Compare with Workspace`.
|
|
7. Claude Code (na reálném repu s trustem): `claude -w test-wt`, nech něco změnit, exit → sleduj cleanup prompt. |