git worktree: come lavorare su più branch contemporaneamente
git worktree permette di collegare a un unico repository più cartelle di lavoro, ciascuna con il proprio branch aperto. Il comando git worktree add ../hotfix main crea accanto al progetto una cartella con il branch main; storia e oggetti sono condivisi e non serve clonare di nuovo nulla.
Cosa fa git worktree
git worktree collega a un unico repository più cartelle di lavoro. Nella cartella principale avete aperto il branch della feature, in quella accanto main per un hotfix urgente, ed entrambi esistono contemporaneamente. Oggetti, commit e branch sono condivisi: un commit fatto in una cartella è subito visibile nell'altra, senza push né fetch.
Senza worktree il cambio di contesto è così: git stash, git switch main, correzione, git switch di ritorno, git stash pop. Se il progetto ha una build lunga o un node_modules pesante, ogni cambio di branch invalida anche le cache. La seconda opzione è clonare di nuovo il repository, ma allora ottenete due copie indipendenti della storia, da sincronizzare tramite il server remoto.
Worktree offre il meglio dei due approcci: cartelle separate, ma un unico database .git. È possibile perché un branch in Git è solo un puntatore a un commit, non una copia dei file, e nulla impedisce a copie di lavoro diverse di guardare puntatori diversi.
Come creare una copia di lavoro aggiuntiva
La forma base del comando è git worktree add <percorso> [<branch>]. Vediamo le varianti principali.
Aprire un branch esistente
cd ~/projects/shop
git worktree add ../shop-main main
Preparing worktree (checking out 'main')
HEAD is now at 3f2c1ab Aggiorna il README
Accanto al progetto comparirà la cartella shop-main con il branch main. Entrateci con un normale cd e lavorate come in qualsiasi repository.
Creare un nuovo branch insieme alla copia di lavoro
git worktree add -b hotfix/payment-timeout ../shop-hotfix main
L'opzione -b crea il branch hotfix/payment-timeout da main e lo apre nella nuova cartella. L'opzione -B fa lo stesso, ma se il branch esiste già lo riporta al commit indicato: usatela con cautela.
Forma breve
git worktree add ../experiment
Se non indicate il branch, Git ne crea uno nuovo con il nome dell'ultimo componente del percorso (qui experiment) a partire dall'HEAD corrente. Se un branch con quel nome esiste già, verrà aperto quello.
Copia di lavoro senza branch
git worktree add --detach ../shop-v1.4 v1.4.0
La modalità detached HEAD è comoda per compilare o verificare una vecchia release a partire dal tag, senza creare branch superflui.
Un branch dal server remoto
git fetch origin
git worktree add ../review-auth feature/auth
Se il branch locale feature/auth non esiste ma ce n'è esattamente uno remoto, origin/feature/auth, Git crea un branch locale con il tracking, come con git switch feature/auth. Così è comodo fare la review della pull request di qualcun altro senza toccare il proprio lavoro.
Come vedere ed eliminare le copie di lavoro
git worktree list
/home/anna/projects/shop a1b2c3d [feature/cart]
/home/anna/projects/shop-hotfix 7e8f9a0 [hotfix/payment-timeout]
/home/anna/projects/shop-v1.4 5d6e7f8 (detached HEAD)
La prima riga è la copia di lavoro principale (main worktree), le altre sono collegate (linked). Per gli script c'è l'output leggibile dalle macchine git worktree list --porcelain.
Quando l'hotfix è stato unito, eliminate la copia di lavoro:
git worktree remove ../shop-hotfix
git branch -d hotfix/payment-timeout
git worktree remove elimina la cartella e le voci di servizio. Se nella copia ci sono modifiche non committate o file non tracciati, il comando si rifiuterà di procedere; aggiungete --force solo se siete sicuri che non servano. Notate che il branch in sé non viene eliminato: va rimosso a parte.
Se la cartella è stata eliminata a mano
Eliminare la cartella dal file manager o con rm -rf lascia in .git/worktrees una voce «orfana», e il branch continua a risultare occupato. Ripulite queste voci:
git worktree prune --verbose
Git lo fa periodicamente anche da solo durante la garbage collection, ma non è necessario aspettare.
Come funziona internamente
In una copia di lavoro collegata, al posto della cartella .git c'è un file .git con una sola riga:
gitdir: /home/anna/projects/shop/.git/worktrees/shop-hotfix
In quella cartella di servizio sono conservati i dati specifici della copia di lavoro: il suo HEAD, il suo index (staging area), i suoi stati di merge e rebase. Tutto il resto è condiviso: oggetti, branch, tag, repository remoti, configurazione e hook.
| Proprio di ogni copia di lavoro | Condiviso da tutte |
|---|---|
| HEAD (branch o commit corrente) | Oggetti e tutta la storia |
| Index (git add) | Branch locali e remoti, tag |
| Merge, rebase, cherry-pick in corso | Stash (refs/stash è condiviso) |
| File nella cartella di lavoro | .git/config e hook |
Dalla tabella emerge un dettaglio poco ovvio: git stash list in qualsiasi copia mostra le stesse voci. È persino comodo: potete mettere da parte le modifiche in una cartella e recuperarle in un'altra.
Il limite principale: un branch, una copia di lavoro
Non si può aprire lo stesso branch in due copie di lavoro. Se ci provate, Git risponde con un errore di questo tipo:
git worktree add ../shop-copy feature/cart
fatal: 'feature/cart' is already used by worktree at '/home/anna/projects/shop'
(nelle versioni più vecchie di Git il testo è «is already checked out at»). Il limite protegge dalla situazione in cui un commit in una cartella cambia silenziosamente il branch sotto i piedi dell'altra. Soluzioni: creare un nuovo branch dallo stesso commit (-b), aprire la copia in modalità --detach oppure, se proprio serve, usare --force conoscendone le conseguenze.
Per lo stesso motivo nella cartella principale non potrete eseguire git switch main finché main è aperto in una copia di lavoro vicina.
Scenari pratici
Hotfix urgente a metà di una feature
git worktree add -b hotfix/null-price ../shop-hotfix main
cd ../shop-hotfix
# correggiamo, testiamo
git commit -am "Correggi il crash con prezzo vuoto"
git push -u origin hotfix/null-price
cd ../shop
git worktree remove ../shop-hotfix
La vostra feature incompleta è rimasta com'era, non è stato necessario mettere nulla nello stash, e l'IDE con il progetto aperto non si è nemmeno accorto del cambio.
Review di una pull request con esecuzione del codice
Una copia separata per la review permette di compilare ed eseguire il branch di un collega, lanciare i test e intanto continuare il proprio lavoro nella finestra accanto dell'editor.
Confrontare il comportamento di due versioni
Due copie con tag diversi si possono avviare in parallelo su porte diverse e confrontare, ad esempio, la velocità di risposta dell'API prima e dopo un'ottimizzazione.
Test e build lunghi
Avviate l'esecuzione completa dei test in una copia e continuate a scrivere codice nell'altra: la build non si romperà perché state modificando dei file.
Più agenti AI in parallelo
Se sui compiti lavorano più agenti o processi, conviene dare a ciascuno la propria copia di lavoro sul proprio branch: non si intralciano a vicenda e i risultati finiscono subito nel repository comune.
Come organizzare le cartelle se usate worktree tutti i giorni
Se le copie di lavoro vi servono ogni giorno, stabilite una struttura, altrimenti le cartelle vicine diventeranno presto un caos. Uno schema diffuso: una cartella padre del progetto, che contiene un repository bare e una cartella per ogni branch:
git clone --bare git@example.com:team/shop.git ~/projects/shop/.bare
cd ~/projects/shop
echo "gitdir: ./.bare" > .git
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
git fetch origin
git worktree add main
git worktree add -b feature/cart feature-cart main
La riga con remote.origin.fetch serve perché un clone bare per impostazione predefinita non configura il tracking dei branch remoti. Il risultato: in ~/projects/shop ci sono le cartelle main e feature-cart, ciascuna con il proprio branch, e nessuna è «più principale» dell'altra.
Una seconda buona abitudine è chiamare la cartella come il branch (sostituendo la barra con un trattino). Così dall'output di git worktree list e dal percorso nel terminale è sempre chiaro dove vi trovate. Infine, eliminate la copia subito dopo il merge del branch: le copie di lavoro vecchie occupano spazio e tengono i branch «occupati».
Errori comuni e insidie
- Dipendenze e build non sono condivise. Ogni copia è una cartella separata, quindi
node_modules, l'ambiente virtuale Python,.enve gli artefatti di build vanno ricreati. I file non tracciati non vengono trasferiti nella nuova copia. - Copia di lavoro dentro la cartella principale. Il comando
git worktree add ./hotfixcrea una cartella dentro il progetto, e la copia principale la vedrà come file non tracciati. Tenete le copie accanto (../) o in una cartella separata, oppure aggiungete il percorso a.gitignore. - Cartella spostata a mano. Il collegamento si rompe. Spostate con
git worktree move ../old ../new, e se l'avete già spostata, eseguitegit worktree repairnella nuova cartella. - La copia su un disco rimovibile sparisce. Perché prune non elimini la voce della copia su un disco scollegato, bloccatela:
git worktree lock --reason "disco esterno" ../shop-usb. - Sottomoduli. Il supporto dei submodule nelle copie di lavoro è limitato; dopo aver creato la copia eseguite
git submodule update --inite controllate il risultato.
Promemoria di git worktree
| Compito | Comando |
|---|---|
| Aprire un branch esistente in una nuova cartella | git worktree add ../dir branch |
| Creare branch e copia | git worktree add -b new-branch ../dir main |
| Copia senza branch (tag, commit) | git worktree add --detach ../dir v1.0 |
| Elenco delle copie | git worktree list |
| Eliminare una copia | git worktree remove ../dir |
| Togliere le voci delle cartelle eliminate | git worktree prune |
| Spostare una copia | git worktree move ../dir ../new-dir |
| Riparare i collegamenti dopo uno spostamento | git worktree repair |
| Proteggere da prune | git worktree lock ../dir |
git worktree, stash o un secondo clone
| Criterio | stash | worktree | secondo clone |
|---|---|---|---|
| Velocità del cambio | Rapido, ma con cambio di branch | Istantaneo: è solo un'altra cartella | Istantaneo |
| Spazio su disco | Minimo | Solo i file di lavoro | Copia completa della storia |
| Sincronizzazione | Non serve | Non serve, la storia è condivisa | Tramite push/fetch |
| Lavoro simultaneo | No | Sì | Sì |
Lo stash resta la scelta migliore per brevi distrazioni di un paio di minuti. Per tutto ciò che dura di più, o quando servono due versioni aperte insieme, è più comodo worktree.
In sintesi
git worktree è un modo semplice per lavorare su più branch contemporaneamente: add crea una cartella, list le mostra, remove e prune le eliminano. La storia è condivisa, mentre HEAD, index e file sono propri di ogni copia; lo stesso branch non può essere aperto in due copie. Come sono fatti i branch e perché passare dall'uno all'altro è così leggero lo vediamo in dettaglio, nella pratica, nel corso su Git.
Domande frequenti
Da quale versione di Git esiste git worktree?
Il comando è comparso in Git 2.5 e da allora è stato molto migliorato, ad esempio remove e move sono stati aggiunti in seguito. In qualsiasi versione moderna di Git tutti i comandi descritti sono disponibili.
Si può fare un commit in una copia di lavoro e vederlo in un'altra?
Sì, la storia è condivisa. Il commit è subito visibile con git log in qualsiasi copia, e si può unire con git merge senza push né fetch.
L'IDE vede più copie di lavoro?
Per l'IDE ogni copia è una normale cartella di progetto, da aprire in una finestra separata. Molti editor mostrano anche l'elenco delle copie di lavoro nell'interfaccia Git integrata.
git worktree remove elimina il branch?
No, vengono eliminate solo la cartella e la voce di servizio. Il branch va eliminato a parte con git branch -d.
git worktree funziona con un repository bare?
Sì, uno schema diffuso è tenere un clone bare e creare da esso una copia di lavoro per ogni branch: in questo caso una cartella «principale» con i file non esiste affatto.
Questo argomento è trattato in modo approfondito, con pratica, nel corso «Git da zero a sviluppatore sicuro».
Vai al corso