La Carla fa tres dies que és a funcionalitat/esborrat-multiple. És una branca llarga: toca app.js, estils.css i el nou diàleg de components-ui. Té el codi a mitges, amb funcions sense acabar i l'aplicació en un estat que ni tan sols arrenca.

I aleshores arriba l'avís: hi ha una fallada en producció i cal publicar una correcció ara.

La seva rutina actual és aquesta:

git stash -u
git switch main
git switch -c correccio/urgent
# ... arreglar, provar, confirmar, publicar ...
git switch funcionalitat/esborrat-multiple
git stash pop
# ... reconstruir mentalment on era ...

Deu vegades al dia. I cada volta té el seu peatge: el stash amb fitxers sense seguiment de vegades dona conflictes en recuperar-lo, cal reconstruir el context mental, el servidor de desenvolupament es reinicia, i des que hi ha submòdul (lliçó 06-05) cada canvi de branca arrossega a més la seva actualització.

La seva idea següent és clonar el repositori dues vegades. Funcionaria, però com veurem té un cost real. Git ofereix una cosa millor i força desconeguda: diversos directoris de treball compartint una única base de dades d'objectes. Es diu git worktree, i amb aquesta lliçó tanquem el mòdul.

Contingut

  1. Què és un worktree
  2. worktree add: el primer directori addicional
  3. Comparació amb clonar dues vegades
  4. El joc complet d'ordres
  5. La regla clau: una branca, un worktree
  6. Com es veu per dins
  7. Casos d'ús reals
  8. Interacció amb stash, submòduls i hooks
  9. Tancament del mòdul 6

  1. Què és un worktree

Recordem l'estructura de la lliçó 01-03. Un repositori Git té dues parts ben diferenciades:

  • El directori .git/: els objectes, les referències, la configuració, el reflog. El repositori de debò.
  • L'arbre de treball (working tree): els fitxers que veus i edites, que són el reflex d'un commit concret.

Fins ara hem donat per fet que n'hi ha un de cada. Però no és obligatori:

Un worktree és un directori de treball addicional, amb el seu propi HEAD, el seu propi índex i els seus propis fitxers, que comparteix la base de dades d'objectes i les referències amb el repositori original.

flowchart TD
    subgraph BD[".git/ — una sola base de dades"]
      O["Objectes: blobs, trees, commits"]
      R["Referències: branques, etiquetes, remots"]
      C["Configuració i reflog"]
    end
    subgraph W1["~/projectes/gestor-tasques"]
      H1["HEAD → funcionalitat/esborrat-multiple"]
      I1["Índex propi"]
      F1["app.js, estils.css... (a mitges)"]
    end
    subgraph W2["~/projectes/gestor-tasques-urgent"]
      H2["HEAD → correccio/urgent"]
      I2["Índex propi"]
      F2["app.js, estils.css... (net)"]
    end
    W1 --> BD
    W2 --> BD

El que es comparteix: objectes, branques, etiquetes, remots, git fetch, configuració del repositori, reflog de les referències.

El que és propi de cada worktree: HEAD, l'índex, els fitxers del disc, l'estat d'operacions en curs (una fusió a mitges, un rebase aturat) i la pila de stash.

El directori original s'anomena worktree principal; els afegits, worktrees enllaçats. Funcionalment són gairebé idèntics.

  1. worktree add: el primer directori addicional

La Carla resol el seu problema amb una ordre:

cd ~/projectes/gestor-tasques
git worktree add ../gestor-tasques-urgent -b correccio/urgent main
Preparing worktree (new branch 'correccio/urgent')
HEAD is now at c8f2a1e Fusiona funcionalitat/filtre-estat

El que acaba de passar:

  • S'ha creat el directori ~/projectes/gestor-tasques-urgent/.
  • Conté una còpia de treball completa del projecte en l'estat de main.
  • S'ha creat la branca correccio/urgent a partir de main i és activa allà.
  • El directori original no s'ha tocat en absolut: continua a funcionalitat/esborrat-multiple, amb tota la seva feina a mitges intacta.
git worktree list
/home/carla/projectes/gestor-tasques           c8f2a1e [funcionalitat/esborrat-multiple]
/home/carla/projectes/gestor-tasques-urgent    c8f2a1e [correccio/urgent]

Ara la Carla treballa al segon directori amb tota normalitat:

cd ../gestor-tasques-urgent
# ... corregir app.js ...
git commit -am "Corregeix l'esborrat quan la tasca te subtasques"
git push -u origin correccio/urgent

I quan acaba, torna:

cd ../gestor-tasques
git status
On branch funcionalitat/esborrat-multiple
Changes not staged for commit:
	modified:   app.js
	modified:   estils.css

Untracked files:
	nou-dialeg.js

Exactament com ho va deixar. Ni stash, ni pop, ni reconstruir el context: l'editor, el servidor de desenvolupament i la finestra del navegador continuen oberts on eren.

Les formes d'invocar add:

Ordre Què fa
git worktree add <ruta> <branca-existent> Obre aquella branca al directori nou
git worktree add <ruta> Crea una branca amb el nom del directori
git worktree add -b <branca-nova> <ruta> [<punt>] Crea la branca i l'obre
git worktree add -B <branca> <ruta> [<punt>] Com -b, però la restableix si ja existeix
git worktree add --detach <ruta> <commit> Detached HEAD en aquell commit, sense branca
git worktree add --track -b <branca> <ruta> origin/<branca> Crea la branca amb seguiment del remot

I una d'útil quan la branca ve del remot:

git fetch
git worktree add ../gestor-tasques-revisio origin/funcionalitat/exportar

Git detecta que funcionalitat/exportar existeix a origin i crea automàticament una branca local amb seguiment (el comportament de --guess-remote, que es pot fixar amb git config worktree.guessRemote true).

  1. Comparació amb clonar dues vegades

L'alternativa evident era git clone una altra vegada. La comparació explica per què worktree és millor gairebé sempre:

git worktree add Segon git clone
Espai al disc Només els fitxers de l'arbre de treball Fitxers + tota la base d'objectes duplicada
Objectes compartits : una sola còpia No: dues còpies independents
Branques visibles Les mateixes a tots els worktrees Cada clon té les seves
Etiquetes Compartides Duplicades i dessincronitzables
git fetch Un de sol actualitza tots Un per clon
Remots i credencials Compartits Cal configurar-los a cadascun
Configuració local Compartida (amb matisos) Independent per clon
Un commit a A, es veu a B? Immediatament Només després de push + fetch
Stash Independent per worktree Independent
Hooks Compartits (un sol .git/hooks) Un per clon
Temps de creació Segons (no hi ha transferència) El que trigui el clon complet
Risc de dessincronització Cap: és un sol repositori Real

El punt que més se subestima és "un commit a A, es veu a B?". Amb dos clons, per portar un commit d'un a l'altre cal passar pel servidor. Amb worktrees, tan bon punt la Carla confirma en un directori, aquell commit ja existeix per a l'altre: hi pot fer git cherry-pick, git rebase o git log immediatament, sense xarxa pel mig.

L'estalvi d'espai, amb xifres: si .git/ ocupa 400 MB (historial llarg, algun binari) i l'arbre de treball 15 MB, un clon extra costa 415 MB i un worktree 15 MB. En repositoris grans la diferència deixa de ser anecdòtica.

Abans existia git clone --shared / --reference per compartir objectes entre clons. Funciona, però és fràgil: si el repositori de referència es mou o es neteja, el clon dependent pot quedar corrupte. git worktree és la solució moderna i segura al mateix problema, i la que s'ha de fer servir.

  1. El joc complet d'ordres

list

git worktree list
git worktree list --porcelain      # format estable, per a scripts
/home/carla/projectes/gestor-tasques           c8f2a1e [funcionalitat/esborrat-multiple]
/home/carla/projectes/gestor-tasques-urgent    3d8f1a6 [correccio/urgent]
/home/carla/projectes/gestor-tasques-v1        b7e2c4a (detached HEAD)
/home/carla/projectes/gestor-tasques-antic     a1b2c3d [experiment] prunable

La marca prunable indica que el directori ja no existeix al disc i el seu registre es pot netejar.

remove

La manera correcta d'eliminar un worktree:

git worktree remove ../gestor-tasques-urgent

Esborra el directori i el seu registre. Si hi ha canvis sense confirmar, s'hi nega —cosa que és una protecció, no una molèstia:

fatal: '../gestor-tasques-urgent' contains modified or untracked files, use --force to delete it
git worktree remove --force ../gestor-tasques-urgent

I compte: remove no esborra la branca. Això va a part:

git branch -d correccio/urgent

prune

Si vas esborrar el directori a mà amb rm -rf (que funciona, però deixa el registre), prune neteja les restes:

git worktree prune
git worktree prune --dry-run -v      # veure què faria sense fer-ho

Git també l'executa sol de tant en tant, i el termini de gràcia es controla amb gc.worktreePruneExpire (per defecte, tres mesos).

move

git worktree move ../gestor-tasques-urgent ~/feina/urgent

Mou el directori i actualitza les rutes internes. Moure'l amb mv a seques trenca els enllaços, així que fes servir sempre aquesta ordre.

lock i unlock

git worktree lock ../gestor-tasques-usb --reason "És al disc extern de còpies"
git worktree unlock ../gestor-tasques-usb

Un worktree bloquejat no es pot fer servir amb prune ni move. És exactament per al cas d'un worktree en una unitat extraïble o un recurs de xarxa: quan la unitat no és muntada, el directori "no existeix" i prune l'esborraria del registre sense més. lock ho impedeix, i el motiu apareix a git worktree list --porcelain perquè se sàpiga per què.

repair

git worktree repair

Reconstrueix els enllaços interns quan alguna cosa els ha trencat: has mogut directoris a mà, has restaurat una còpia de seguretat, o has reanomenat el repositori principal.

Taula resum:

Ordre Què fa
git worktree add <ruta> [<branca>] Crea un worktree nou
git worktree list Els llista tots, amb la seva branca i el seu commit
git worktree remove <ruta> N'elimina un (amb --force si hi ha canvis)
git worktree prune Neteja registres de worktrees ja esborrats
git worktree move <origen> <destinacio> En mou un actualitzant les rutes
git worktree lock/unlock <ruta> En protegeix un de prune i move
git worktree repair [<rutes>] Repara els enllaços interns trencats

  1. La regla clau: una branca, un worktree

Aquesta és la restricció fonamental, i cal entendre-la perquè explica la meitat dels missatges d'error que veuràs:

Una mateixa branca no pot estar activa en dos worktrees alhora.

cd ~/projectes/gestor-tasques-urgent
git switch funcionalitat/esborrat-multiple
fatal: 'funcionalitat/esborrat-multiple' is already used by worktree at
'/home/carla/projectes/gestor-tasques'

I el mateix en crear:

git worktree add ../altre-mes funcionalitat/esborrat-multiple
fatal: 'funcionalitat/esborrat-multiple' is already used by worktree at
'/home/carla/projectes/gestor-tasques'

Per què existeix la restricció. Una branca és un punter que avança en confirmar (lliçó 03-01). Si dos worktrees tinguessin la mateixa branca activa, un commit en un mouria la branca sota els peus de l'altre: el segon es trobaria que el seu HEAD apunta a un commit que ell no ha creat, i el seu arbre de treball deixaria de correspondre a res coherent. Git prohibeix la situació en lloc de deixar que passi.

No és una limitació, és una protecció. I té tres sortides quan de debò necessites el mateix codi dues vegades:

# A) En detached HEAD: sense branca per moure, no hi ha conflicte
git worktree add --detach ../revisio-nomes-lectura funcionalitat/esborrat-multiple

# B) En un commit concret, que és el mateix
git worktree add --detach ../versio-1.0 v1.0.0

# C) Una branca nova des del mateix punt
git worktree add -b experiment/altra-via ../experiment funcionalitat/esborrat-multiple

L'opció A és la que més es fa servir: per llegir o compilar una branca no cal tenir-la activa com a branca.

I una conseqüència pràctica que convé saber: git branch -d es nega a esborrar una branca que sigui activa en un altre worktree, i git rebase o git merge tampoc no hi poden operar des de fora. Per localitzar on és:

git worktree list | grep nom-de-la-branca

  1. Com es veu per dins

Reprenem la lliçó 01-04 i el model de dades, perquè el mecanisme és elegant i explica tot l'anterior.

Al worktree principal, .git és un directori:

cd ~/projectes/gestor-tasques
ls -ld .git
drwxrwxr-x 9 carla carla 4096 ag.  1 11:23 .git

En un worktree enllaçat, .git és un fitxer de text:

cd ~/projectes/gestor-tasques-urgent
ls -l .git
cat .git
-rw-rw-r-- 1 carla carla 78 ag.  1 11:25 .git
gitdir: /home/carla/projectes/gestor-tasques/.git/worktrees/gestor-tasques-urgent

Una sola línia que diu: "el meu repositori és allà". És exactament el mateix mecanisme que fan servir els submòduls de la lliçó 06-05, on el .git del submòdul és un fitxer que apunta a .git/modules/<nom> del pare.

I al repositori principal:

ls ~/projectes/gestor-tasques/.git/worktrees/
gestor-tasques-urgent/  gestor-tasques-v1/
ls ~/projectes/gestor-tasques/.git/worktrees/gestor-tasques-urgent/
HEAD  ORIG_HEAD  commondir  gitdir  index  logs/  ORIG_HEAD
Fitxer Contingut
HEAD El HEAD propi d'aquell worktree
index El seu índex propi (l'àrea de preparació)
gitdir La ruta absoluta del directori de treball al qual serveix
commondir Ruta al .git comú, on hi ha els objectes i les refs
logs/HEAD El reflog d'aquell worktree

I aquí hi ha l'explicació completa del model:

  • HEAD i index són per worktree → cadascun pot ser en una branca diferent i tenir els seus propis canvis preparats.
  • objects/ i refs/ són al commondir → les branques, les etiquetes i els objectes són els mateixos per a tots, i per això un commit en un es veu a l'instant a l'altre.

Amb això s'entén també per què la restricció de l'apartat 5 és inevitable: hi ha un sol fitxer refs/heads/funcionalitat/esborrat-multiple, i no pot ser el HEAD de dos directoris que confirmen per separat.

Hi ha fins i tot una notació per consultar el HEAD d'un altre worktree:

git rev-parse main@{worktree-principal}   # sintaxi avançada, rarament necessària
git worktree list --porcelain             # l'habitual

I una nota sobre configuració: per defecte, .git/config és compartit per tots els worktrees. Si necessites que un tingui configuració pròpia, existeix extensions.worktreeConfig:

git config extensions.worktreeConfig true
git config --worktree core.sparseCheckout true

És un cas avançat i poc freqüent, però convé saber que existeix si et trobes un config.worktree dins de .git/worktrees/<nom>/.

  1. Casos d'ús reals

Cas 1: el hotfix sense tocar el que tens a mitges

El de la Carla, i el més comú. Un worktree permanent per a urgències:

git worktree add ../gestor-tasques-hotfix main

Quan arriba l'avís, cd ../gestor-tasques-hotfix, git pull, es crea la branca, s'arregla i es publica. Sense stash, sense canviar de branca, sense perdre el context.

Cas 2: comparar dues versions en execució

En Bruno ha de comprovar si un problema de rendiment existia a la versió 1.0:

git worktree add --detach ../gestor-tasques-v1 v1.0.0
# Terminal 1
cd ~/projectes/gestor-tasques && python3 -m http.server 8000

# Terminal 2
cd ~/projectes/gestor-tasques-v1 && python3 -m http.server 8001

Dos servidors, dues pestanyes del navegador, les dues versions funcionant alhora. Comparar així és incomparablement més fiable que anar alternant branques i recordar com era.

Cas 3: compilar una branca mentre treballes en una altra

Una compilació completa de gestor-tasques triga quatre minuts. Amb un sol directori, aquests quatre minuts són d'espera, perquè qualsevol edició embruta el resultat. Amb worktrees:

git worktree add ../gestor-tasques-build funcionalitat/esborrat-multiple-rc
cd ../gestor-tasques-build && npm run build &
cd ~/projectes/gestor-tasques    # continuar treballant mentre compila

Cas 4: revisar la branca d'un company

L'Ana ha de revisar la pull request d'en Bruno, però és a mitja feina pròpia:

git fetch
git worktree add --detach ../revisio origin/funcionalitat/exportar
cd ../revisio
# ... executar, llegir, provar ...
cd .. && git worktree remove revisio

Sense --detach també funcionaria, però per revisar no cal branca local, i així s'evita acumular branques de revisió.

Cas 5: un rebase llarg sense bloquejar la feina

Un git rebase -i amb conflictes (lliçó 05-02) deixa el repositori en un estat intermedi. Si apareix alguna cosa urgent, quedes atrapat: rebase --abort i a començar de nou. Amb un worktree dedicat, el rebase es queda aturat al seu directori i tu treballes en un altre. Com que l'estat de les operacions en curs és propi de cada worktree, no interfereixen.

Cas 6: bisect sense aturar-se

git bisect (lliçó 06-02) fa desenes de checkout al teu directori. Si és una bisecció llarga amb compilacions, la pots llançar en un worktree a part:

git worktree add --detach ../gestor-tasques-bisect main
cd ../gestor-tasques-bisect
git bisect start main v1.0.0
git bisect run /tmp/provar-esborrat.sh

Mentrestant, el teu directori principal continua a la teva branca, intacte. En acabar, git bisect reset i git worktree remove.

Cas 7: documentació en una branca òrfena

Alguns projectes publiquen la documentació en una branca independent (gh-pages i similars). Amb worktrees:

git worktree add ../gestor-tasques-docs gh-pages

S'edita la documentació al seu directori i el codi al seu, amb historials separats i sense canviar de branca mai.

  1. Interacció amb stash, submòduls i hooks

Amb git stash

La pila de stash és pròpia de cada worktree. Un git stash list al directori principal no mostra el que s'ha desat en un altre:

cd ~/projectes/gestor-tasques
git stash list
stash@{0}: WIP on funcionalitat/esborrat-multiple: 8d4f2a7 Delega els esdeveniments...
cd ../gestor-tasques-urgent
git stash list
(buit)

Tècnicament, refs/stash es desa per worktree. És coherent amb el model —el stash és feina a mitges d'un arbre concret— però sorprèn la primera vegada.

I la conclusió pràctica de tot això: els worktrees no substitueixen stash, sinó que redueixen molt la necessitat de fer-lo servir. stash continua sent l'eina correcta per apartar una cosa durant dos minuts dins de la mateixa branca; el worktree ho és per treballar en dues branques durant dies.

Situació Eina
Apartar canvis dos minuts per fer un pull git stash
Provar una cosa ràpida a la mateixa branca git stash
Treballar en dues branques durant hores o dies git worktree
Atendre urgències sense perdre el context git worktree
Comparar dues versions en execució git worktree
Desar feina abans de canviar de màquina git stash o una branca WIP

Amb submòduls

Els worktrees i els submòduls (lliçó 06-05) conviuen, però cal saber dues coses:

  • Els submòduls no s'inicialitzen sols en un worktree nou. Després de l'add, toca:
git worktree add ../gestor-tasques-urgent -b correccio/urgent main
cd ../gestor-tasques-urgent
git submodule update --init --recursive
  • Els repositoris interns dels submòduls viuen al .git/modules/ comú, així que els objectes es comparteixen igual que els del pare: la inicialització no torna a baixar res de la xarxa, només fa checkout. És ràpida.

El suport de worktrees dins de submòduls ha millorat molt en les versions recents de Git, però continua sent el terreny on apareixen més rareses. Si alguna cosa es descol·loca, git worktree repair sol arreglar-ho.

Amb hooks

Els hooks són compartits: hi ha un sol .git/hooks/ (o un sol core.hooksPath, lliçó 06-01) per a tots els worktrees. Un pre-commit instal·lat funciona a tots automàticament, cosa que és un avantatge.

El matís: un hook que assumeixi rutes absolutes o que doni per fet un directori concret es pot confondre. Els hooks s'executen amb el directori de treball posat a l'arrel del worktree actiu, així que fer servir rutes relatives és el correcte. I si un hook necessita distingir on és:

git rev-parse --show-toplevel      # arrel del worktree actual
git rev-parse --git-common-dir     # el .git compartit
git rev-parse --git-dir            # el .git/worktrees/<nom> d'aquest worktree

Amb el rendiment i el manteniment

Un apunt breu, perquè el tema complet és d'una altra lliçó: els worktrees comparteixen la base d'objectes, així que un git gc afecta tots i Git té cura de no eliminar objectes referenciats des de qualsevol d'ells. Un worktree registrat però el directori del qual ja no existeix pot, en canvi, mantenir vius objectes innecessàriament: per això convé executar git worktree prune de tant en tant.

Tot el relatiu a git gc, git maintenance i el rendiment en repositoris grans és el tema de la lliçó 08-06: Consells de Rendiment; els clons parcials, sparse-checkout i les tècniques d'escalat, el de la 10-04.

  1. Tancament del mòdul 6

Amb aquesta lliçó tanques el bloc d'eines. Repassant el que ha canviat en la manera de treballar de l'equip de gestor-tasques:

  • Hooks (06-01): comprovacions automàtiques a pre-commit, commit-msg i pre-push, versionades amb core.hooksPath. Ajuden contra el descuit, però el que és obligatori es comprova al servidor.
  • git bisect (06-02): cerca binària que converteix 214 commits en 8 proves, automatitzable amb bisect run i els seus codis de sortida.
  • git blame (06-03): la història de cada línia, amb -w, -C i --ignore-rev per travessar el soroll, i git log -L per veure l'evolució completa.
  • git log avançat i àlies (06-04): --graph, --first-parent, --simplify-by-decoration, --left-right, formats amb colors, shortlog, i els àlies que converteixen tot això en una paraula.
  • Submòduls (06-05): un punter a un commit d'un altre repositori, amb reproductibilitat exacta a canvi de fricció, i comparats amb subtree, paquets i monorepo.
  • git worktree (06-06): diversos directoris de treball sobre una única base d'objectes.

I una idea que travessa tot el mòdul: l'historial de Git no és només un registre del que va passar, és una base de dades consultable. Qui va escriure cada línia, en quin commit va canviar un comportament, què s'ha integrat a main aquest mes, quina versió exacta de la biblioteca feia servir la versió 1.0. Totes aquestes preguntes tenen resposta exacta, i ara saps com demanar-la.

El que ve

L'equip domina l'eina. L'Ana, en Bruno i la Carla saben construir l'historial, manipular-lo amb criteri, consultar-lo a fons i automatitzar comprovacions sobre ell.

El que no han acordat encara és com treballar junts. I aquestes preguntes ja no són tècniques:

  • Quan en Bruno acaba una funcionalitat, com la proposa? Empeny directament a main? Obre una pull request? I si no té permís d'escriptura al repositori?
  • Quan l'Ana revisa la feina de la Carla, què mira, com comenta i quan aprova? Què fa un revisor que no sigui repetir el que ja diu el linter?
  • Quines branques existeixen i per a què serveix cadascuna? Hi ha una branca develop? Branques de versió? O tothom integra a main diverses vegades al dia?
  • Quan es publica una versió? Què cal haver passat abans que un canvi arribi a producció?

No hi ha una resposta única: hi ha fluxos de treball diferents, cadascun amb la seva lògica, els seus avantatges i el seu tipus d'equip. Un projecte de codi obert amb centenars de col·laboradors externs no pot funcionar com un equip de tres persones que desplega cinc vegades al dia.

Al mòdul 7: Estratègies de Col·laboració i Flux de Treball veurem els forks i les pull requests com a mecanisme per proposar canvis, les revisions de codi i com es fan bé, i els tres grans models de ramificació —Git Flow, GitHub Flow i Trunk Based Development— comparats amb criteri per saber quin encaixa en cada situació. I tancarem amb la integració contínua: les comprovacions automàtiques que, aquesta vegada sí, ningú no es pot saltar amb un --no-verify.

Comencem per com es proposa un canvi, a la lliçó 07-01: Forks i Pull Requests.

Errors Habituals i Consells

Error 1: intentar obrir la mateixa branca en dos worktrees. Git ho impedeix i et diu on és activa. Fes servir --detach si només vols llegir o compilar.

Error 2: esborrar el directori amb rm -rf. Funciona, però deixa el registre brut. Fes servir git worktree remove, o git worktree prune després.

Error 3: moure el directori amb mv. Trenca els enllaços interns. Fes servir git worktree move, o git worktree repair si ja ho has fet.

Error 4: oblidar que remove no esborra la branca. Treure el worktree deixa la branca viva; esborra-la a part amb git branch -d.

Error 5: esperar que els submòduls s'inicialitzin sols. Cal executar git submodule update --init --recursive a cada worktree nou.

Error 6: buscar un stash al worktree equivocat. La pila és pròpia de cadascun. Si no apareix, mira a l'altre directori.

Error 7: crear worktrees dins del mateix repositori. git worktree add ./temporal funciona, però el directori apareix com a contingut sense seguiment del repositori principal. Crea'ls fora, com a germans del directori original.

Error 8: acumular worktrees oblidats. Ocupen disc i mantenen branques ocupades. git worktree list de tant en tant, i remove dels que sobren.

Consell 1: adopta una convenció de noms. gestor-tasques, gestor-tasques-hotfix, gestor-tasques-v1. Amb ../<projecte>-<proposit> mai no et perds.

Consell 2: tingues un worktree permanent per a urgències. Sempre a main, sempre net. És el que més vegades et salvarà el dia.

Consell 3: crea un àlies. Amb el que hem après a la lliçó 06-04:

git config --global alias.wt "worktree list"
git config --global alias.nou '!f() { git worktree add "../$(basename "$PWD")-$1" -b "$1"; }; f'

git nou correccio-urgent crea ../gestor-tasques-correccio-urgent amb aquella branca.

Consell 4: --detach per a tot el que sigui només lectura. Revisar, compilar, comparar o bisecar no necessita branca local, i així no xoques amb la regla d'una branca per worktree.

Consell 5: un git fetch n'hi ha prou per a tots. És un sol repositori: no repeteixis el fetch a cada directori.

Consell 6: comprova la teva versió de Git. worktree existeix des de la 2.5, però move, remove i repair van arribar després (2.17 i 2.30). En versions antigues, algunes operacions són manuals.

Exercicis

Exercici 1: el flux del hotfix

  1. Crea un repositori amb main i una branca funcionalitat/llarga amb canvis sense confirmar (modificats i sense seguiment).
  2. Sense fer stash, crea un worktree a ../projecte-hotfix amb una branca nova correccio/urgent des de main.
  3. Confirma una correcció al worktree nou.
  4. Torna al directori original i comprova que els teus canvis sense confirmar continuen exactament igual.
  5. Comprova des del directori original que el commit del hotfix ja existeix (git log correccio/urgent), sense haver fet cap push ni fetch.
  6. Elimina el worktree i la branca.

Exercici 2: la restricció d'una branca per worktree

  1. Amb el repositori anterior, intenta crear un worktree amb una branca que ja sigui activa en un altre. Anota el missatge d'error.
  2. Aconsegueix el mateix codi en un segon directori fent servir --detach.
  3. Comprova amb git worktree list que un apareix amb branca i l'altre com a (detached HEAD).
  4. Intenta esborrar amb git branch -d una branca activa en un altre worktree i observa què passa.

Exercici 3: l'anatomia per dins

  1. En un worktree enllaçat, comprova que .git és un fitxer i mostra'n el contingut.
  2. Localitza el directori corresponent a .git/worktrees/ del principal i llista'n el contingut.
  3. Compara el HEAD de tots dos worktrees.
  4. Fes un git stash en un i comprova que git stash list a l'altre és buit.
  5. Esborra un worktree amb rm -rf, comprova que continua apareixent a git worktree list (marcat com a prunable) i neteja'l amb prune.

Solucions

Solució 1:

mkdir /tmp/practica-worktree && cd /tmp/practica-worktree
git init -q -b main
echo "<html><body></body></html>" > index.html
echo "console.info('arrencada');" > app.js
git add . && git commit -q -m "Afegeix l'esquelet de l'aplicacio"

git switch -qc funcionalitat/llarga
echo "// feina a mitges, no compila" >> app.js
echo "esborrany sense acabar" > notes.txt

git status --short
 M app.js
?? notes.txt
git worktree add ../projecte-hotfix -b correccio/urgent main
Preparing worktree (new branch 'correccio/urgent')
HEAD is now at 4f8a2e6 Afegeix l'esquelet de l'aplicacio
cd ../projecte-hotfix
git status --short          # net
echo "console.info('correccio aplicada');" >> app.js
git commit -qam "Corregeix l'arrencada quan falta el contenidor"
git log --oneline
7d3a8f4 Corregeix l'arrencada quan falta el contenidor
4f8a2e6 Afegeix l'esquelet de l'aplicacio
cd /tmp/practica-worktree
git status --short
cat notes.txt
 M app.js
?? notes.txt
esborrany sense acabar

Intactes. Ni stash ni pop.

git log --oneline correccio/urgent
7d3a8f4 Corregeix l'arrencada quan falta el contenidor
4f8a2e6 Afegeix l'esquelet de l'aplicacio

El commit fet a l'altre directori es veu immediatament: és la mateixa base d'objectes. Amb dos clons hauria calgut push + fetch.

git worktree remove ../projecte-hotfix
git worktree list
git branch
/tmp/practica-worktree  9c2f7e4 [funcionalitat/llarga]
  correccio/urgent
* funcionalitat/llarga
  main

La branca continua viva: remove no l'esborra.

git branch -D correccio/urgent

Solució 2:

git worktree add ../altre funcionalitat/llarga
fatal: 'funcionalitat/llarga' is already used by worktree at '/tmp/practica-worktree'
git worktree add --detach ../altre funcionalitat/llarga
Preparing worktree (detached HEAD 9c2f7e4)
HEAD is now at 9c2f7e4 Afegeix l'esquelet de l'aplicacio
git worktree list
/tmp/practica-worktree  9c2f7e4 [funcionalitat/llarga]
/tmp/altre              9c2f7e4 (detached HEAD)

Mateix commit, mateix contingut, sense conflicte: a ../altre no hi ha cap branca que es pugui moure.

cd /tmp/altre
git branch -d funcionalitat/llarga
error: Cannot delete branch 'funcionalitat/llarga' checked out at '/tmp/practica-worktree'

Git protegeix la branca activa en qualsevol worktree, no només en l'actual.

Solució 3:

cd /tmp/altre
ls -l .git
cat .git
-rw-rw-r-- 1 carla carla 42 ag.  1 12:10 .git
gitdir: /tmp/practica-worktree/.git/worktrees/altre
ls /tmp/practica-worktree/.git/worktrees/altre/
HEAD  commondir  gitdir  index  logs  ORIG_HEAD
cat /tmp/practica-worktree/.git/worktrees/altre/HEAD
cat /tmp/practica-worktree/.git/HEAD
cat /tmp/practica-worktree/.git/worktrees/altre/commondir
9c2f7e4a8b3d5f1e6c9a2b7d4f8c1e5a3b6d9f2c
ref: refs/heads/funcionalitat/llarga
../..

El worktree enllaçat té un hash directe (detached), el principal una referència simbòlica a la seva branca, i commondir apunta al .git compartit on hi ha els objectes i les refs.

# 4. El stash és per worktree
cd /tmp/practica-worktree
git stash -u
git stash list
stash@{0}: WIP on funcionalitat/llarga: 9c2f7e4 Afegeix l'esquelet de l'aplicacio
cd /tmp/altre
git stash list
(buit)
cd /tmp/practica-worktree && git stash pop     # recuperar la feina
# 5. Esborrat a mà i prune
rm -rf /tmp/altre
git worktree list
/tmp/practica-worktree  9c2f7e4 [funcionalitat/llarga]
/tmp/altre              9c2f7e4 (detached HEAD) prunable

El registre continua allà, marcat com a prunable.

git worktree prune --dry-run -v
git worktree prune
git worktree list
Removing worktrees/altre: gitdir file points to non-existent location
/tmp/practica-worktree  9c2f7e4 [funcionalitat/llarga]

Net. Amb git worktree remove en lloc de rm -rf, aquest últim pas no hauria calgut.

Conclusió

git worktree resol un problema quotidià amb una idea simple i ben construïda. L'essencial:

  • Un worktree és un directori de treball addicional amb el seu propi HEAD i índex, que comparteix objectes i referències amb el repositori original.
  • Davant de clonar dues vegades: no duplica la base d'objectes, comparteix branques, etiquetes, remots i hooks, un sol fetch serveix per a tots, i un commit fet en un es veu a l'instant a l'altre, sense passar pel servidor.
  • git worktree add <ruta> [<branca>] el crea en segons; -b crea branca nova i --detach obre un commit sense branca.
  • El joc complet és add, list, remove, prune, move, lock/unlock i repair. Fes servir remove en lloc de rm -rf i move en lloc de mv; lock protegeix els worktrees en unitats extraïbles.
  • Una branca no pot estar activa en dos worktrees alhora. No és una limitació capriciosa: evita que un commit mogui la branca sota els peus d'un altre directori. La sortida per a lectura i compilació és --detach.
  • Per dins, el .git del worktree enllaçat és un fitxer amb una línia gitdir: que apunta a .git/worktrees/<nom>, on viuen el seu HEAD, el seu index i el seu reflog; els objectes i les refs són al commondir compartit. És el mateix mecanisme que fan servir els submòduls.
  • Casos d'ús que es guanyen el lloc: hotfix sense perdre el context, comparar dues versions en execució, compilar una branca mentre treballes en una altra, revisar la branca d'un company, i aïllar un rebase llarg o una bisecció.
  • El stash és propi de cada worktree; els hooks són compartits; els submòduls cal inicialitzar-los a cada worktree nou.
  • I la relació amb stash: no el substitueix, però en redueix molt l'ús. stash per a minuts dins d'una branca; worktree per a dies entre diverses.

Amb això es tanca el mòdul 6 i el bloc tècnic del curs. L'equip de gestor-tasques ja sap construir, manipular, consultar i automatitzar el seu historial. El que necessita ara és posar-se d'acord: com es proposa un canvi, com es revisa i quin flux de branques seguir. Això és el mòdul 7, i comença a la lliçó 07-01: Forks i Pull Requests.

Dominant Git: De Principiant a Avançat

Mòdul 1: Introducció a Git

Mòdul 2: Operacions Bàsiques de Git

Mòdul 3: Branques i Fusió

Mòdul 4: Treballant amb Repositoris Remots

Mòdul 5: Operacions Avançades de Git

Mòdul 6: Eines i Tècniques de Git

Mòdul 7: Estratègies de Col·laboració i Flux de Treball

Mòdul 8: Bones Pràctiques i Consells de Git

Mòdul 9: Resolució de Problemes i Depuració

Mòdul 10: Git al Món Real

© Copyright 2026. Tots els drets reservats