Git Worktree per sviluppare branch in parallelo: un workflow pulito e isolato
Il problema tipico dello sviluppo parallelo non è creare un altro branch. Git rende quella parte banale. Il vero problema è assicurarsi che ciò che stai testando sia davvero il branch appena modificato, che il servizio stia partendo dalla directory corretta e che il commit finale non trascini dentro file non correlati.
Alla fine ho adottato un pattern molto più pulito: mantenere stabile la directory del repository principale e usare git worktree per assegnare a ogni feature branch una propria directory di lavoro isolata. Da quando lo faccio in modo coerente, portare avanti più feature in parallelo sulla stessa macchina è diventato molto meno soggetto a errori.
Se stai cercando sviluppo parallelo di branch Git, un workflow con Git worktree o un processo pratico standard per branch isolati, questo articolo tratta esattamente quel caso.
Perché ho smesso di affidarmi al continuo cambio di branch
Il problema centrale non è la creazione dei branch. È la contaminazione.
In un’unica directory di repository, cicli ripetuti di checkout tendono a produrre sempre gli stessi problemi:
- pensi di stare testando una nuova feature, ma il servizio attivo proviene ancora da un’altra directory
- artefatti di build di una feature finiscono in un altro branch
git add .raccoglie in silenzio file che non dovrebbero mai essere committati- bugfix e feature iniziano a condividere lo stesso workspace disordinato
È esattamente il tipo di problema che Git worktree risolve bene. Non ti aiuta solo a creare un branch più velocemente: dà a ogni branch un posto fisicamente separato in cui vivere.
Le regole sulle directory che tengo fisse
Per mantenere il workflow noioso nel senso buono, tratto alcune convenzioni come non negoziabili:
- repository principale:
/Users/kuangyongjie/charting_library - root dei worktree:
/Users/kuangyongjie/worktrees - formato branch:
codex/<feature-name> - branch principale:
master
Il repository principale serve quindi per stabilità e merge, mentre il lavoro sulle feature avviene in percorsi come:
/Users/kuangyongjie/worktrees/hotspot-ff
Sembra un dettaglio, ma cambia molto. Quando il percorso stesso ti dice dove sei, diventa molto più difficile confondere il repo principale con un workspace di feature.
Il flusso standard è breve, ma ogni passaggio conta
Per prima cosa assicurati che esista la root dei worktree:
mkdir -p /Users/kuangyongjie/worktrees
Poi crea un nuovo worktree e un nuovo branch a partire dal repository principale:
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
L’output atteso è:
codex/<feature-name>
Questa conferma è importante. Da quel momento in poi sviluppo, build e verifica locale dovrebbero rimanere all’interno di "$WT".
Sviluppo e test solo nella directory del branch
Una volta creato il worktree, provo a essere rigoroso: build ed esecuzione soltanto dalla directory di quel branch.
Per esempio, se il frontend è in una cartella annidata:
cd "$WT/trendradar-service/trendradar-web"
npm run build
# production obfuscated build
# npm run build:multi-layer
Una delle false piste di debugging più comuni è: “ho cambiato il codice, ma la pagina sembra ancora vecchia”. Molto spesso il codice è corretto. È il processo che sta girando da un’altra directory.
Quando qualcosa sembra stale, controllo prima il cwd del processo:
lsof -nP -iTCP:<port> | sed -n '1,5p'
ps -p <pid> -o pid,ppid,command
lsof -p <pid> | rg "cwd"
Devi verificare che la directory di lavoro corrente punti davvero a:
/Users/kuangyongjie/worktrees/<feature-name>/...
Se non lo fa, probabilmente stai testando il branch sbagliato indipendentemente da ciò che Git mostra.
In questo workflow uso quasi mai git add .
Qui rimango volutamente conservativo.
Con worktree paralleli preferisco mettere in stage solo i file interessati invece di prendere tutta la directory. È troppo facile committare accidentalmente residui runtime, snapshot locali, cache o file generati.
I colpevoli tipici sono:
__pycache__*.dbsnapshot_*.DS_Store
Il mio schema abituale assomiglia quindi a:
cd "$WT"
git add <file1> <file2> <file3>
git status --short
git commit -m "feat/fix: <summary>"
Quel controllo extra con git status --short è piccolo, ma elimina parecchio rumore.
Fai merge solo dal repository principale
Quando la feature è pronta, non faccio merge dall’interno del worktree. Torno al repository principale e lo faccio lì:
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>
La parte importante non è tanto --no-ff, quanto essere davvero sul branch principale e nella directory del repository principale prima del merge.
Se compare:
MERGE_HEAD exists
di solito significa che il merge precedente non è terminato correttamente. In quel caso:
git merge --abort
e poi ripeti la sequenza pull/merge.
Se devi anche fare push:
cd /Users/kuangyongjie/charting_library
git push <remote> master
Un dettaglio pratico: su questa macchina il remote più comune si chiama spesso central, non origin. È una caratteristica dell’ambiente, non un problema di Git worktree.
Quando uso fast-forward invece di lasciare un merge commit
A volte il requisito è leggermente diverso: testare in una directory branch isolata e poi riportare tutto su main senza creare un merge commit.
In quel caso ha senso un flusso fast-forward. Per esempio:
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
Poi esegui il servizio soltanto da quel worktree:
cd /Users/kuangyongjie/worktrees/hotspot-ff/trendradar-service
./venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 9544
E verifica il cwd da un altro terminale:
lsof -nP -iTCP:9544 -sTCP:LISTEN
ps -p <PID> -o pid,ppid,command
lsof -a -p <PID> -d cwd -Fn
Vale la pena ripeterlo: “il branch ha superato i test” significa poco se il processo non è mai partito dalla directory corretta.
Le regole che considero ormai obbligatorie
Se pensi di usare i worktree nel lungo periodo, manterrei almeno queste regole rigide:
- una feature per directory worktree
- un task o una conversazione per worktree
- eseguire
git branch --show-currentprima di iniziare - eseguire
git status --shortprima di committare - fare merge soltanto dal repository principale
master
Nessuna è complicata. Ed è proprio per questo che funzionano.
Problemi comuni
La pagina locale mostra ancora il risultato vecchio
Non dare subito per scontato che la modifica al codice sia fallita.
Controlla prima che il cwd del processo sia dentro il worktree target. Poi verifica di aver davvero ricostruito gli asset dalla directory di quel branch.
fatal: 'origin' does not appear to be a git repository
Di solito il nome del remote è sbagliato. Esegui:
git remote -v
e fai push al remote effettivo. In questo ambiente spesso è central.
MERGE_HEAD exists
In genere significa che l’ultimo merge è rimasto incompleto. Esegui:
git merge --abort
e ricomincia il flusso di merge.
Ho modificato solo file frontend. Devo riavviare il backend?
Di solito no. Se gli asset statici sono stati ricostruiti e deployati correttamente, spesso basta un refresh della cache.