El atasco del checkout único
Estoy desarrollando una app de menú bar en macOS. Tengo tres features en el backlog: un sparkline de consumo, notificaciones nativas, y un widget de escritorio. Las tres son independientes. Las tres las voy a hacer con Claude Code.
El problema: Claude Code trabaja en un directorio. Un directorio tiene una rama. Y git checkout es como una rotonda de un solo carril: solo pasa uno.
Si quiero avanzar las tres a la vez, mis opciones clásicas son:
-
Stash ping-pong:
git stash, cambiar rama, trabajar,git stash pop, rezar para que no haya conflictos. Repetir hasta la locura o la jubilación, lo que llegue primero. -
Clonar el repo tres veces: Funciona, pero ahora tengo tres copias de
.git/, tres históricos independientes, y ungit fetchque hacer en cada uno. Un desperdicio. -
Aceptar la vida serial: Una feature detrás de otra. Seguro, predecible, y lento como un merge sort a mano.
Ninguna mola. Pero hay una cuarta opción que lleva en git desde 2015 y que casi nadie usa.
Worktrees: la solución que ya tenías instalada
Un worktree es un segundo directorio de trabajo que comparte el mismo repositorio .git. Sin copias, sin clones, sin magia negra.
La analogía: tu repo es una biblioteca. Hasta ahora tenías una mesa donde solo podías tener un libro abierto. Un worktree es poner más mesas. Cada una con un libro diferente abierto, pero todas sacando de la misma estantería.
~/code/miapp/ ← mesa 1 (main)
.git/ ← la biblioteca (una sola)
~/code/miapp-sparkline/ ← mesa 2 (feature/sparkline)
.git ← fichero, no carpeta (puntero a la biblioteca)
~/code/miapp-notificaciones/ ← mesa 3 (feature/notifications)
.git ← otro puntero
Cada directorio es un checkout completo con todos los ficheros. Puedes compilar en uno, correr tests en otro, y tener tu agente de IA trabajando en el tercero. Al mismo tiempo.
Crearlo es una línea
Desde tu repo principal:
git worktree add ../miapp-sparkline -b feature/sparkline
git worktree add ../miapp-notificaciones -b feature/notifications
Ya está. Dos directorios nuevos, cada uno en su rama, compartiendo toda la base de datos git. Nada de clonar, nada de configurar remotes, nada de duplicar histórico.
Lo que comparten y lo que no
Esto es importante. Los worktrees comparten todo el repo: commits, ramas, tags, remotes, hooks, configuración. Si haces un commit en el worktree de sparkline, puedes verlo inmediatamente desde el de notificaciones sin hacer fetch ni nada, porque es la misma base de datos.
Lo que no comparten:
- Los ficheros en disco (cada mesa tiene su copia de trabajo)
- El staging area (cada uno tiene su propio
git add) - El HEAD (cada uno apunta a su rama)
Dicho en cristiano: el estado de «en qué estoy trabajando» es privado de cada worktree. Todo lo demás es común.
El workflow con coding agents
Aquí es donde se pone interesante. Con worktrees, puedes tener literalmente varios agentes trabajando en paralelo sobre el mismo proyecto:
# Terminal 1: Claude Code en sparkline
cd ~/code/miapp-sparkline
claude
# Terminal 2: Claude Code en notificaciones
cd ~/code/miapp-notificaciones
claude
# Terminal 3: main intacto, la app corriendo
cd ~/code/miapp
make run
Cada instancia de Claude tiene su propio directorio, su propia rama, su propio .build/. No se pisan. No compiten por el index. No necesitan hacer stash de nada.
Y como comparten la base de datos git, cuando uno de los agentes termina y hace push, los demás ya ven esa rama.
Mergear: exactamente igual que siempre
Los worktrees no cambian nada del flujo de merge. Son ramas normales en directorios separados:
# Opción A: merge local
cd ~/code/miapp
git merge feature/sparkline
git merge feature/notifications
# Opción B: PRs (lo habitual)
cd ~/code/miapp-sparkline
git push -u origin feature/sparkline
# Crear PR en GitHub/Gitea, review, merge
Cuando terminas, limpias:
git worktree remove ../miapp-sparkline
git branch -d feature/sparkline # si ya se mergeó
Los pitfalls que nadie te cuenta
1. Una rama, un worktree
No puedes tener main checkeada en dos worktrees a la vez. Es por diseño: evita que dos directorios modifiquen el mismo HEAD y se corrompan. Si necesitas un segundo checkout de main, crea una rama temporal.
2. El primer build es desde cero
Cada worktree tiene su propio directorio de build. La primera compilación va a ser lenta. Después, cada worktree mantiene su cache independiente, que es precisamente la ventaja sobre el git checkout clásico (que te invalida el cache cada vez que cambias de rama).
3. Ficheros locales no trackeados
Tu .env.local, configuraciones de editor, ficheros que no están en git… no se copian al worktree nuevo. Tendrás que recrearlos o hacer symlinks.
4. Apps con estado compartido en disco
Si tu app escribe datos en ~/Library/Application Support/ o similar, dos instancias de la app desde distintos worktrees van a competir por el mismo fichero. No es un problema del worktree, es un problema de correr dos instancias de la misma app. La solución: no correr dos a la vez, o parametrizar el directorio de datos por build.
5. No borres el directorio a mano
Si haces rm -rf del worktree en vez de usar git worktree remove, git sigue pensando que la rama está ocupada. Ejecuta git worktree prune para limpiar las referencias huérfanas.
6. El remote no sabe nada
Los worktrees son 100% locales. Gitea, GitHub, GitLab… ningún remote sabe que existen. Solo ven git push normales con ramas normales. Es como preguntar si tu servidor tiene problemas con que uses Vim o VS Code: no lo sabe, no le afecta.
Buenas prácticas
Convención de nombres: pon los worktrees como hermanos del repo original, con un sufijo descriptivo:
~/code/miapp/ ← main
~/code/miapp-sparkline/ ← feature
~/code/miapp-notifications/ ← feature
~/code/miapp-hotfix-login/ ← hotfix
Así un ls ~/code/miapp* te muestra todo de un vistazo.
Un worktree por feature, no por capricho: crea worktrees para trabajo que realmente va a ser paralelo. Si vas a hacer una cosa detrás de otra, una rama normal con checkout es suficiente.
Limpia cuando termines: los worktrees abandonados son como las ramas que nadie borra — se acumulan y confunden. git worktree list es tu amigo.
No edites el mismo fichero desde dos worktrees: técnicamente puedes, cada uno tiene su copia. Pero si ambos modifican el mismo archivo, tendrás conflictos al mergear. Intenta que las features toquen áreas distintas del código.
Propuesta de workflow completa
Para los que queráis un flujo de trabajo ordenado, aquí va el que uso yo:
# 1. Crear worktrees para las features del sprint
cd ~/code/miapp
git worktree add ../miapp-feat-a -b feature/feat-a
git worktree add ../miapp-feat-b -b feature/feat-b
# 2. Lanzar un agente en cada uno
cd ~/code/miapp-feat-a && claude # terminal 1
cd ~/code/miapp-feat-b && claude # terminal 2
# 3. Ir mergeando conforme terminan
cd ~/code/miapp-feat-a
git push -u origin feature/feat-a # crear PR
# 4. Limpiar lo que ya se mergeó
git worktree remove ../miapp-feat-a
git branch -d feature/feat-a
# 5. Ver qué queda vivo
git worktree list
El ciclo es: crear → trabajar en paralelo → push/PR → merge → limpiar. Cada worktree vive lo que vive la feature, ni más ni menos.
Para cerrar
Los worktrees llevan en git desde la versión 2.5 (julio de 2015). Más de diez años. Y la mayoría de la gente sigue haciendo git stash como si estuviéramos en 2010.
Con la llegada de los coding agents, el cuello de botella ya no es la velocidad a la que escribes código — es la velocidad a la que puedes cambiar de contexto. Y los worktrees eliminan ese cambio de contexto por completo: no cambias de rama, cambias de directorio. cd en vez de checkout.
Que es, al fin y al cabo, lo que siempre debimos haber hecho.
TL;DR: git worktree add ../nombre -b rama crea un segundo directorio de trabajo sobre el mismo repo. Sin copias, sin stash, sin invalidar caches. Perfecto para tener varios coding agents trabajando en paralelo. Limpia con git worktree remove cuando termines.
Read this article in English.



