Git Worktree para desarrollar ramas en paralelo: un flujo limpio y aislado
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:
/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:
mkdir -p /Users/kuangyongjie/worktrees
Después crea un worktree y una nueva rama desde el repositorio principal:
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:
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:
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:
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:
/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__*.dbsnapshot_*.DS_Store
Mi patrón normal se parece más a esto:
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í:
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:
MERGE_HEAD exists
normalmente significa que el merge anterior no terminó correctamente. En ese caso:
git merge --abort
y después repite la secuencia pull/merge.
Si también necesitas hacer push:
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:
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:
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:
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-currentantes de empezar - ejecutar
git status --shortantes 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:
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:
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é.