# Git Worktree para desarrollar ramas en paralelo: un flujo limpio y aislado

> Canonical: https://vxi.me/es/posts/git-worktree-parallel-development/
> Locale: es-es
> Published: 2026-03-25
> Updated: 2026-03-25
> Markdown: https://vxi.me/es/posts/git-worktree-parallel-development.md

El problema habitual del desarrollo en paralelo no es crear otra rama. Git hace esa parte trivial. El problema es asegurarte de que lo que estás probando sea realmente la rama que acabas de modificar, que el servicio se esté ejecutando desde el directorio correcto y que el commit final no arrastre archivos que no tienen nada que ver.

Con el tiempo acabé usando un patrón mucho más limpio: mantener estable el directorio principal del repositorio y utilizar `git worktree` para dar a cada rama de feature su propio directorio de trabajo aislado. Desde que lo hago de forma consistente, ejecutar varias features en paralelo en la misma máquina se ha vuelto mucho menos propenso a errores.

Si buscas desarrollo paralelo con ramas Git, un workflow con Git worktree o un proceso estándar para ramas aisladas, este artículo trata exactamente de eso.

## Por qué dejé de depender del cambio constante de ramas

El problema central no es crear ramas. Es la contaminación.

En un único directorio de repositorio, los ciclos repetidos de `checkout` tienden a crear siempre las mismas clases de problemas:

- crees que estás probando una nueva feature, pero el servicio en ejecución sigue viniendo de otro directorio
- los artefactos de build de una feature se filtran a otra rama
- `git add .` recoge silenciosamente archivos que nunca deberían commitearse
- los bugfixes y el trabajo de features empiezan a compartir el mismo workspace desordenado

Eso es precisamente lo que Git worktree resuelve muy bien. No solo te ayuda a crear una rama más rápido. Le da a cada rama un lugar físicamente separado donde vivir.

## Las reglas de directorio que mantengo fijas

Para que el workflow sea aburrido en el buen sentido, convierto unas pocas convenciones en reglas no negociables:

- repositorio principal: `/Users/kuangyongjie/charting_library`
- raíz de worktrees: `/Users/kuangyongjie/worktrees`
- formato de rama: `codex/<feature-name>`
- rama principal: `master`

El repositorio principal se reserva para estabilidad y merges, mientras que el trabajo de features ocurre en rutas como:

```text
/Users/kuangyongjie/worktrees/hotspot-ff
```

Parece un detalle pequeño, pero cambia mucho. Cuando la propia ruta ya indica dónde estás, es bastante más difícil confundir el repo principal con un workspace de feature.

## El flujo estándar es corto, pero cada paso importa

Primero asegúrate de que existe la raíz de worktrees:

```bash
mkdir -p /Users/kuangyongjie/worktrees
```

Después crea un worktree y una nueva rama desde el repositorio principal:

```bash
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
```

La salida esperada es:

```text
codex/<feature-name>
```

Esta confirmación importa. A partir de ahí, desarrollo, builds y validación local deberían permanecer dentro de `"$WT"`.

## Haz todo el desarrollo y las pruebas dentro del directorio de la rama

Una vez creado el worktree, intento ser estricto: construir y ejecutar únicamente desde el directorio de esa rama.

Por ejemplo, si el frontend vive en una carpeta interna:

```bash
cd "$WT/trendradar-service/trendradar-web"
npm run build
# production obfuscated build
# npm run build:multi-layer
```

Una de las falsas pistas de debugging más habituales es: “he cambiado el código, pero la página sigue viéndose vieja”. Muchas veces el código está bien. El proceso simplemente se está ejecutando desde otro sitio.

Cuando algo parece desactualizado, reviso primero el `cwd` del proceso:

```bash
lsof -nP -iTCP:<port> | sed -n '1,5p'
ps -p <pid> -o pid,ppid,command
lsof -p <pid> | rg "cwd"
```

Lo que quieres confirmar es que el directorio de trabajo actual apunte realmente a:

```text
/Users/kuangyongjie/worktrees/<feature-name>/...
```

Si no es así, probablemente estás probando la rama equivocada, independientemente de lo que diga Git.

## Casi nunca utilizo `git add .` en este flujo

Aquí prefiero ser deliberadamente conservador.

Con worktrees en paralelo, stageo solo los archivos objetivo en vez de recoger todo el directorio. Es demasiado fácil commitear por accidente restos de runtime, snapshots locales, cachés o archivos generados.

Los sospechosos habituales son:

- `__pycache__`
- `*.db`
- `snapshot_*`
- `.DS_Store`

Mi patrón normal se parece más a esto:

```bash
cd "$WT"
git add <file1> <file2> <file3>
git status --short
git commit -m "feat/fix: <summary>"
```

Ese `git status --short` extra es pequeño, pero detecta bastante ruido.

## Haz merge de vuelta solo desde el repositorio principal

Cuando la feature está lista, no hago el merge desde dentro del worktree. Vuelvo al repositorio principal y hago merge allí:

```bash
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>
```

Lo importante no es tanto `--no-ff` como verificar que realmente estés en la rama principal y en el directorio principal antes de hacer merge.

Si aparece:

```text
MERGE_HEAD exists
```

normalmente significa que el merge anterior no terminó correctamente. En ese caso:

```bash
git merge --abort
```

y después repite la secuencia pull/merge.

Si también necesitas hacer push:

```bash
cd /Users/kuangyongjie/charting_library
git push <remote> master
```

Un detalle práctico: en esta máquina el remote habitual suele llamarse `central`, no `origin`. Eso es un detalle del entorno, no un problema de Git worktree.

## Cuándo uso fast-forward en lugar de dejar un merge commit

A veces la necesidad cambia: probar dentro de un directorio de rama aislado y después volver a main sin crear un merge commit.

Ahí tiene sentido un flujo de fast-forward. Por ejemplo:

```bash
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
```

Después ejecuta el servicio únicamente desde ese worktree:

```bash
cd /Users/kuangyongjie/worktrees/hotspot-ff/trendradar-service
./venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 9544
```

Y desde otra terminal verifica el `cwd`:

```bash
lsof -nP -iTCP:9544 -sTCP:LISTEN
ps -p <PID> -o pid,ppid,command
lsof -a -p <PID> -d cwd -Fn
```

Vale la pena repetir esta comprobación porque decir “la rama pasó las pruebas” sirve de poco si el proceso nunca se ejecutó desde el directorio correcto.

## Las reglas que ahora considero obligatorias

Si vas a utilizar worktrees a largo plazo, mantendría al menos estas reglas:

- una feature por directorio de worktree
- una tarea o una conversación por worktree
- ejecutar `git branch --show-current` antes de empezar
- ejecutar `git status --short` antes de cada commit
- hacer merge únicamente desde el repositorio principal `master`

Ninguna regla es complicada. Precisamente por eso funcionan.

## Problemas habituales

### La página local sigue mostrando el resultado antiguo

No asumas de inmediato que el cambio de código falló.

Primero comprueba que el `cwd` del proceso esté dentro del worktree objetivo. Después verifica que realmente reconstruiste los assets desde ese directorio de rama.

### `fatal: 'origin' does not appear to be a git repository`

Normalmente el nombre del remote es incorrecto. Ejecuta:

```bash
git remote -v
```

y haz push al remote real. En este entorno suele ser `central`.

### `MERGE_HEAD exists`

Normalmente el último merge quedó sin terminar. Ejecuta:

```bash
git merge --abort
```

y reinicia el flujo de merge.

### Solo cambié archivos de frontend. ¿Tengo que reiniciar el backend?

Normalmente no. Si los assets estáticos se reconstruyeron y desplegaron correctamente, suele bastar con refrescar la caché.
