# Git Worktree für parallele Branch-Entwicklung: ein sauber isolierter Workflow

> Canonical: https://vxi.me/de/posts/git-worktree-parallel-development/
> Locale: de-de
> Published: 2026-03-25
> Updated: 2026-03-25
> Markdown: https://vxi.me/de/posts/git-worktree-parallel-development.md

Das übliche Problem bei paralleler Entwicklung ist nicht, einen weiteren Branch anzulegen. Das macht Git trivial. Schwierig ist sicherzustellen, dass das, was man gerade testet, wirklich der eben geänderte Branch ist, dass der Dienst aus dem richtigen Verzeichnis läuft und dass der finale Commit keine fremden Dateien mitnimmt.

Ich bin schließlich bei einem deutlich saubereren Muster gelandet: Das Hauptverzeichnis des Repositories bleibt stabil, und mit `git worktree` bekommt jeder Feature-Branch ein eigenes isoliertes Arbeitsverzeichnis. Seit ich das konsequent so mache, ist parallele Arbeit an mehreren Features auf derselben Maschine wesentlich weniger fehleranfällig.

Wenn du nach paralleler Branch-Entwicklung mit Git, einem Git-worktree-Workflow oder einem praktischen Standardprozess für isolierte Branches suchst, geht es hier genau darum.

## Warum ich nicht mehr ständig zwischen Branches wechsle

Das Kernproblem ist nicht das Erstellen von Branches, sondern Kontamination.

In einem einzigen Repository-Verzeichnis führen wiederholte `checkout`-Zyklen häufig zu denselben Problemen:

- du glaubst, ein neues Feature zu testen, aber der laufende Dienst stammt noch aus einem anderen Verzeichnis
- Build-Artefakte eines Features gelangen in einen anderen Branch
- `git add .` nimmt unbemerkt Dateien auf, die niemals committed werden sollten
- Bugfixes und Feature-Arbeit teilen sich zunehmend denselben unordentlichen Workspace

Genau das löst Git worktree sehr gut. Es hilft nicht nur, schneller einen Branch anzulegen, sondern gibt jedem Branch einen physisch getrennten Ort.

## Die Verzeichnisregeln, die bei mir fest sind

Damit der Workflow angenehm langweilig bleibt, behandle ich einige Konventionen als nicht verhandelbar:

- Haupt-Repository: `/Users/kuangyongjie/charting_library`
- Worktree-Root: `/Users/kuangyongjie/worktrees`
- Branch-Format: `codex/<feature-name>`
- Haupt-Branch: `master`

Das Haupt-Repository dient also Stabilität und Merge, während die eigentliche Feature-Arbeit zum Beispiel hier stattfindet:

```text
/Users/kuangyongjie/worktrees/hotspot-ff
```

Das wirkt wie eine Kleinigkeit, verändert aber viel. Wenn schon der Pfad zeigt, wo man sich befindet, verwechselt man Haupt-Repo und Feature-Workspace wesentlich seltener.

## Der Standardablauf ist kurz, aber jeder Schritt zählt

Zuerst sicherstellen, dass das Worktree-Root existiert:

```bash
mkdir -p /Users/kuangyongjie/worktrees
```

Dann vom Haupt-Repository aus einen neuen Worktree samt Branch anlegen:

```bash
REPO=/Users/kuangyongjie/charting_library
WT=/Users/kuangyongjie/worktrees/<feature-name>
BRANCH=codex/<feature-name>
BASE=master

# If the remote is available, update master first
# git -C "$REPO" pull --rebase central "$BASE"

git -C "$REPO" worktree add "$WT" -b "$BRANCH" "$BASE"
cd "$WT"
git branch --show-current
```

Erwartete Ausgabe:

```text
codex/<feature-name>
```

Diese Bestätigung ist wichtig. Ab diesem Punkt sollten Entwicklung, Build-Befehle und lokale Verifikation vollständig innerhalb von `"$WT"` stattfinden.

## Entwicklung und Tests nur im Branch-Verzeichnis

Sobald der Worktree existiert, bin ich hier streng: Build und Run nur aus diesem Branch-Verzeichnis.

Liegt das Frontend beispielsweise in einem Unterordner:

```bash
cd "$WT/trendradar-service/trendradar-web"
npm run build
# production obfuscated build
# npm run build:multi-layer
```

Eine der häufigsten falschen Debug-Spuren lautet: „Ich habe den Code geändert, aber die Seite sieht noch alt aus.“ Sehr oft ist der Code korrekt. Der Prozess läuft nur aus einem anderen Verzeichnis.

Wenn etwas veraltet wirkt, prüfe ich deshalb zuerst die `cwd` des Prozesses:

```bash
lsof -nP -iTCP:<port> | sed -n '1,5p'
ps -p <pid> -o pid,ppid,command
lsof -p <pid> | rg "cwd"
```

Zu bestätigen ist, dass das aktuelle Arbeitsverzeichnis tatsächlich hierhin zeigt:

```text
/Users/kuangyongjie/worktrees/<feature-name>/...
```

Tut es das nicht, testest du wahrscheinlich den falschen Branch – unabhängig davon, was Git anzeigt.

## In diesem Workflow verwende ich fast nie `git add .`

Hier bleibe ich bewusst konservativ.

Bei parallelen Worktrees stage ich lieber nur die gewünschten Dateien, statt das gesamte Verzeichnis einzusammeln. Laufzeitreste, lokale Snapshots, Caches oder generierte Dateien landen sonst zu leicht versehentlich im Commit.

Typische Kandidaten sind:

- `__pycache__`
- `*.db`
- `snapshot_*`
- `.DS_Store`

Mein normales Muster sieht daher eher so aus:

```bash
cd "$WT"
git add <file1> <file2> <file3>
git status --short
git commit -m "feat/fix: <summary>"
```

Der zusätzliche Check mit `git status --short` ist klein, fängt aber viel unnötigen Müll ab.

## Zurück mergen nur aus dem Haupt-Repository

Ist das Feature fertig, merge ich nicht aus dem Worktree selbst. Ich gehe zurück ins Haupt-Repository und merge dort:

```bash
cd /Users/kuangyongjie/charting_library
git branch --show-current   # must be master

# If the remote is available, update first
# git pull --rebase central master

git merge --no-ff codex/<feature-name>
```

Wichtiger als `--no-ff` ist, wirklich auf dem Haupt-Branch und im Hauptverzeichnis zu sein, bevor der Merge beginnt.

Falls diese Meldung erscheint:

```text
MERGE_HEAD exists
```

ist der vorherige Merge meist nicht sauber abgeschlossen worden. Dann:

```bash
git merge --abort
```

und anschließend Pull/Merge erneut durchführen.

Wenn zusätzlich gepusht werden soll:

```bash
cd /Users/kuangyongjie/charting_library
git push <remote> master
```

Ein praktisches Detail: Auf dieser Maschine heißt der übliche Remote häufig `central`, nicht `origin`. Das ist eine Besonderheit der Umgebung, kein Git-worktree-Problem.

## Wann ich Fast-Forward statt Merge-Commit verwende

Manchmal ist die Anforderung anders: in einem isolierten Branch-Verzeichnis testen und danach ohne zusätzlichen Merge-Commit zurückführen.

Dafür passt ein Fast-Forward-Ablauf. Zum Beispiel:

```bash
cd /Users/kuangyongjie/charting_library
git checkout master
git pull --rebase central master

git worktree add /Users/kuangyongjie/worktrees/hotspot-ff -b codex/hotspot-ff master
```

Dann den Dienst ausschließlich aus diesem Branch-Worktree starten:

```bash
cd /Users/kuangyongjie/worktrees/hotspot-ff/trendradar-service
./venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 9544
```

Und in einem zweiten Terminal die `cwd` prüfen:

```bash
lsof -nP -iTCP:9544 -sTCP:LISTEN
ps -p <PID> -o pid,ppid,command
lsof -a -p <PID> -d cwd -Fn
```

Dieser Check lohnt sich immer wieder: „Der Branch hat den Test bestanden“ bedeutet wenig, wenn der Prozess nie aus dem richtigen Verzeichnis lief.

## Die Regeln, die für mich inzwischen Pflicht sind

Wenn Worktrees langfristig genutzt werden sollen, würde ich mindestens diese Regeln hart halten:

- ein Feature pro Worktree-Verzeichnis
- ein Task oder eine Unterhaltung pro Worktree
- vor Arbeitsbeginn `git branch --show-current` ausführen
- vor jedem Commit `git status --short` ausführen
- nur aus dem Haupt-Repository auf `master` mergen

Keine dieser Regeln ist kompliziert. Genau deshalb funktionieren sie.

## Häufige Probleme

### Die lokale Seite zeigt noch das alte Ergebnis

Nicht sofort annehmen, dass die Codeänderung fehlgeschlagen ist.

Zuerst prüfen, ob die `cwd` des laufenden Prozesses im Ziel-Worktree liegt. Danach sicherstellen, dass die Assets tatsächlich aus diesem Branch-Verzeichnis neu gebaut wurden.

### `fatal: 'origin' does not appear to be a git repository`

Meist ist einfach der Remote-Name falsch. Ausführen:

```bash
git remote -v
```

und zum tatsächlich vorhandenen Remote pushen. In dieser Umgebung ist das häufig `central`.

### `MERGE_HEAD exists`

Das bedeutet meist, dass der letzte Merge unvollständig blieb:

```bash
git merge --abort
```

Danach den Merge-Ablauf neu starten.

### Ich habe nur Frontend-Dateien geändert. Muss das Backend neu gestartet werden?

In der Regel nicht. Wenn die statischen Assets korrekt neu gebaut und deployed wurden, reicht oft ein Cache-Refresh.
