Git worktrees y Claude Code: agentes en paralelo sin conflictos

Cómo usar git worktrees para correr varios Claude Code en paralelo sobre checkouts aislados: montar, integrar y limpiar sin pisarte las ramas.

Git worktrees y Claude Code: agentes en paralelo sin conflictos

El cuello de botella de programar con IA no es el modelo. Es que solo tienes un working directory. En cuanto lanzas un segundo Claude Code sobre el mismo checkout, o cambias de rama para arrancar otra tarea y le rompes el contexto al agente que ya estaba trabajando, has serializado algo que no tenía por qué serializarse. Los git worktrees eliminan esa serialización: cada agente trabaja en su propia copia física del repo, aislada, sin conflictos de index. Aquí está el flujo completo que uso para tener dos o tres agentes en marcha a la vez, cómo integro lo que producen y cómo limpio después sin dejar basura.

¿Por qué un solo checkout serializa tu trabajo con IA?

Porque git tiene un único index y un único HEAD por directorio de trabajo, y un agente que edita ficheros vive en ese estado compartido. Mientras Claude Code toca archivos en tu checkout, ese checkout es suyo. Si abres otra sesión para atacar un bug distinto, tienes tres malas opciones: esperar a que la primera termine, cambiar de rama por debajo (y dejar al primer agente con ficheros que ya no cuadran con su plan), o hacer copias del repo a mano y rezar para no confundir cuál es cuál.

Cambiar de rama es el error más silencioso. El agente tenía en su ventana de contexto un mapa mental del árbol de ficheros. Le haces un git switch a otra rama, le cambian tres archivos bajo los pies, y a partir de ahí cada edición que hace parte de una realidad que ya no existe. No falla en voz alta. Simplemente empieza a producir diffs que no aplican.

Lo que escasea es el directorio de trabajo, y eso sí se puede clonar.

¿Qué es exactamente un git worktree?

Un worktree es un segundo directorio de trabajo enlazado al mismo repositorio. Tiene su propio HEAD, su propio index y sus propios ficheros en disco, pero comparte el object database y las ramas con el repo original[1]. Cuando haces un commit en un worktree, ese commit existe inmediatamente para todos los demás, porque los objetos viven una sola vez en el .git común.

Diagrama de arquitectura mostrando un repositorio Git con un object database compartido (commits, ramas y stash) en el centro, y tres worktrees en paralelo a la derecha, cada uno con su propio HEAD, index y directorio de trabajo, ejecutando su propio agente Claude Code de forma aislada.
Todos los worktrees comparten el mismo object database (commits, ramas, stash), pero cada uno tiene su propio HEAD, index y directorio de ficheros. Por eso dos agentes pueden trabajar en paralelo sin pisarse el staging ni la rama activa.

El detalle de implementación que conviene tener claro: en un worktree enlazado, .git no es un directorio, es un fichero de texto que apunta a $GIT_DIR/worktrees/<nombre> dentro del repo principal[1]. Por eso no estás duplicando la historia ni los objetos. Duplicas solo el árbol de ficheros del checkout. Un repo con años de historia y un working tree pequeño te cuesta, en cada worktree nuevo, más o menos lo que pesa ese árbol de ficheros, no lo que pesa el .git.

Lo que se comparte y lo que no es justo la línea que hace útil el patrón:

Cambiar de rama en un checkoutUn worktree por tarea
Contexto del agenteSe rompe en cada switch: el árbol de ficheros cambia bajo la sesión abiertaEstable. Cada agente ve siempre su mismo directorio
Build / node_modulesUno solo, que hay que reconstruir tras cada cambio de ramaIndependiente por worktree; cada uno instala lo suyo
Conflictos de indexConstantes si dos procesos tocan el staging a la vezImposibles: cada worktree tiene su propio index
Coste en discoCero extraEl peso del working tree (los objetos se comparten)
IntegraciónYa estás en el repogit merge desde el principal; los commits ya están ahí

Montar un worktree para un agente aislado

git worktree add crea el directorio y checkea una rama en una sola orden. La forma que uso casi siempre crea la rama nueva a la vez, para no tener que hacerlo en dos pasos:

# Crea un directorio de trabajo aislado y la rama feature-a en una sola orden
git worktree add ../repo-feature-a -b feature-a

# Checkout de una rama que YA existe (por ejemplo, un hotfix que estabas revisando)
git worktree add ../repo-hotfix hotfix-123

Con -b feature-a git parte de tu HEAD actual y crea la rama nueva sin tocar tu checkout[1]. Sin -b y sin nombre de rama, git te crea una rama automáticamente con el nombre del último componente de la ruta, cosa que rara vez es lo que quieres. Sé explícito con -b o pasa una rama existente.

Los pongo como hermanos del repo (../repo-feature-a), no dentro de él, para que ningún watcher, linter o git status del checkout principal se meta en medio. Para ver qué tienes montado:

git worktree list
# /Users/tu/repo             a1b2c3d [main]
# /Users/tu/repo-feature-a   e4f5c6d [feature-a]
# /Users/tu/repo-hotfix      b7a8c9e [hotfix-123]

Cada línea es un directorio real con su HEAD. Ninguno interfiere con los otros.

¿Cómo corro dos o tres Claude Code a la vez sin que se pisen?

Una terminal por worktree, un claude por terminal. Ese es todo el truco. Como cada worktree es un directorio físico con su propio index, dos agentes editando a la vez no compiten por nada: no hay staging compartido, no hay HEAD compartido, no hay una rama que uno le cambie al otro.

# Terminal 1: feature nueva
cd ../repo-feature-a && npm install && claude

# Terminal 2: hotfix en paralelo
cd ../repo-hotfix && npm install && claude

El npm install de cada línea no es decorativo. node_modules no se comparte entre worktrees, y a menudo esa es exactamente la ventaja que quieres: la feature nueva instaló una dependencia que el hotfix no debería ver todavía, y como los árboles están separados, no colisionan. La contrapartida es que pagas una instalación por worktree. Si tu node_modules es enorme, esto se nota en tiempo y en disco, y es una de las contrapartidas reales del patrón.

A partir de aquí, cada sesión es una unidad de trabajo con nombre. “El agente de feature-a” y “el agente del hotfix” son cosas distintas en directorios distintos, no dos pestañas que confundes a las tres de la tarde. Si ya tenías esta costumbre con Claude Code antes, el flujo detallado con la integración del CLI profundiza en cómo encajarlo en el día a día.

¿Cómo integro el trabajo de vuelta?

Con un git merge normal desde tu checkout principal, sin sincronizar nada. Este es el punto donde el modelo mental de mucha gente falla: creen que tienen que “traerse” los commits del worktree, como si fuera un remoto. No. Los worktrees comparten el mismo object database, así que en cuanto el agente de feature-a hace commit, esa rama ya está actualizada para todo el repo.

# Desde tu checkout principal
git switch main
git merge feature-a   # los commits ya viven en el repo compartido; no hay fetch ni sync

No hace falta que la rama de origen esté “checkeada” en tu directorio para mergearla. feature-a puede seguir viva y con su agente trabajando en ../repo-feature-a mientras tú integras desde main. Antes de mergear a ciegas lo que produjo un agente, léelo: revisar en git lo que la IA generó es la mitad del trabajo, sobre todo cuando el diff lo escribió un modelo a toda velocidad.

El stash también es compartido, por cierto. Vive en refs/stash, que es un ref del repo común. Un git stash que hiciste en un worktree lo ves desde cualquier otro. Útil de saber, y peligroso si esperabas lo contrario.

¿Cómo limpio los worktrees cuando termino?

Con git worktree remove, nunca con rm -rf. Esta es la disciplina que separa un flujo limpio de un ~/code lleno de carpetas fantasma.

Flowchart con cinco pasos: git worktree add crea directorio y rama, el agente Claude Code hace commits aislado, git merge integra la rama desde el checkout principal, git worktree remove borra el directorio, y git branch -d borra la rama.
El ciclo completo de un worktree usado para un agente: crear, trabajar aislado, integrar con merge y limpiar en dos pasos (remove del directorio, -d de la rama).
git worktree remove ../repo-feature-a   # solo si el worktree está limpio
git worktree prune                       # limpia metadata de carpetas borradas a mano

git worktree remove borra el directorio y su metadata de golpe, pero se niega si el worktree tiene cambios sin commitear o ficheros sin trackear[1]. Ese “no” es una red de seguridad, no un obstáculo: te está avisando de que hay trabajo que ibas a tirar. Si de verdad quieres descartarlo, -f fuerza; -f -f para un worktree bloqueado.

git worktree prune es para cuando ya la liaste. Borraste la carpeta a mano con rm -rf y git no se enteró, así que sigue teniendo la metadata colgando en $GIT_DIR/worktrees[1]. prune recorre esa lista, detecta los directorios que ya no existen y limpia lo que quedó huérfano. Con -n lo ves sin ejecutarlo.

La trampa de la rama es sutil: quitar un worktree no borra su rama. git worktree remove ../repo-feature-a elimina el directorio, pero feature-a sigue existiendo. Si ya la mergeaste y no la quieres, la borras aparte con git branch -d feature-a. Son dos operaciones, y olvidarlo es cómo acabas con cuarenta ramas muertas.

¿Cuándo NO usar worktrees?

Cuando el coste por checkout supera lo que ganas en paralelismo. El patrón no es gratis, y hay escenarios donde el trajín de cambiar de rama era más barato que mantener tres directorios vivos.

Si tu setup de dependencias es lento y pesado (un node_modules de gigas, un entorno que tarda minutos en construirse, contenedores por proyecto), cada worktree nuevo te cobra ese peaje entero. Para una tarea de cinco minutos no compensa. Tampoco compensa si tus tareas comparten estado en disco fuera de git: una base de datos local, un .env con puertos fijos, un servidor de desarrollo que solo puede escuchar en un sitio. Dos agentes que quieren el puerto 3000 no se salvan con worktrees; se pelean igual.

Y si vas a lanzar un solo agente y esperar a que acabe, no montes nada. Los worktrees resuelven concurrencia. Sin concurrencia real, son complejidad sin premio.

Errores comunes

Intentar checkear la misma rama en dos worktrees

Git no te deja, y hace bien. Dos worktrees con la misma rama tendrían dos HEADs apuntando al mismo sitio y dos indexes divergiendo: un estado incoherente esperando a corromperse. El mensaje es explícito:

git worktree add ../otra-copia feature-a
# fatal: 'feature-a' is already checked out at '/Users/tu/repo-feature-a'

La alternativa (ramificar o soltar el HEAD) la tienes en las preguntas frecuentes.

Asumir que node_modules o el build se comparten

No se comparten. Todo lo que git no trackea (dependencias, artefactos de build, cachés) arranca vacío en cada worktree. Esto sorprende a quien lo imagina “como una rama pero más rápida”: es una copia física del working tree que necesita su propio arranque.

Dejar decenas de worktrees huérfanos

El fallo aburrido que a todos nos pasa. Terminas una tarea, cierras la terminal, y el worktree se queda. Multiplícalo por semanas y tienes veinte directorios ocupando disco, cada uno con su node_modules. La cura es un ritual de cierre: cuando mergeas, remove el worktree y branch -d la rama en la misma respiración.

Checklist de implementación

  • Cada tarea paralela vive en su propio worktree creado con git worktree add, no en copias manuales del repo
  • Los worktrees cuelgan como hermanos del repo (../repo-tarea), no dentro del checkout principal
  • Cada worktree hace su propio install de dependencias antes de arrancar el agente
  • Ningún worktree comparte puerto, base de datos local ni .env con otro que corra a la vez
  • La integración se hace con git merge desde el principal, sin intentar sincronizar commits entre worktrees
  • Al terminar, cada worktree se elimina con git worktree remove y su rama con git branch -d
  • git worktree prune se ejecuta de vez en cuando para limpiar metadata de carpetas borradas a mano

Si el problema de fondo no es el patrón sino git en sí, el curso Git de cero a profesional monta la base sobre la que este flujo tiene sentido. Y si quieres el resto de patrones para trabajar con git cuando la IA escribe la mitad del código, están en la guía completa de desarrollo asistido con git.

Un concepto nuevo cada semana

Fuentes

  1. Documentación oficial de git worktree (git-scm.com): sintaxis de add, list, remove y prune, la regla de que git rechaza checkear una rama ya usada por otro worktree, el hecho de que .git en un worktree enlazado es un fichero, y qué se comparte (objetos y refs) frente a qué es por worktree (HEAD e index).

Preguntas Frecuentes

¿Puedo mergear una rama que sigue abierta en otro worktree?

Sí, y es lo normal cuando integras el trabajo de un agente sin pararlo. feature-a puede seguir con su sesión viva en ../repo-feature-a mientras haces git merge feature-a desde main: los commits ya están en el object database común, así que no hay fetch ni sync de por medio.

¿Puedo tener la misma rama en dos worktrees a la vez?

No, y el porqué lo tienes en los errores comunes de arriba. Lo que sí puedes es abrir dos vistas del mismo punto de la historia, ramificando o soltando el HEAD:

# Rama nueva desde el mismo commit
git worktree add ../otra -b feature-a-v2
# HEAD suelto, sin rama asociada
git worktree add --detach ../otra feature-a

¿Cuánto disco ocupa cada worktree?

Poco más que el peso de tu working tree: los objetos de git (toda la historia) se comparten y no se duplican. Lo que sí se duplica es lo que git no trackea, empezando por node_modules, que en proyectos con dependencias pesadas acaba pesando más que el propio checkout.

¿Cómo lo limpio si borré la carpeta a mano?

Con git worktree prune, que ya viste en la sección de limpieza: recorre $GIT_DIR/worktrees, detecta las entradas cuyo directorio ya no existe y las quita. Para la próxima, git worktree remove <ruta> en vez de rm -rf y te ahorras el paso.