Saltar al contenido principal
Jordi Izquierdo Montalbán
Blog

Una rama por fase, ADR y spec antes de código: mi flujo de trabajo en Git

Cómo organizo ramas, commits y decisiones en agente-telegram, qué me enseñó tener 29 commits sin empujar y en qué se parece y se diferencia de trabajar en equipo con GitFlow.

5 min de lectura -

Cuando alguien me pregunta si sé Git, la respuesta útil es enseñar qué reglas sigo, cuáles me costó escribir y dónde no las cumplo. Casi todo sale de agente-telegram, un proyecto personal con un solo autor (yo): cómodo para tener disciplina, mal ejemplo de trabajo en equipo.

Una rama por fase

En agente-telegram cada fase del plan vive en su propia rama, con nombres como fase/f12-interfaz-y-redactor. Cuando la fase termina y el arnés de pruebas está entero en verde, la mergeo a main con --no-ff, para que el historial conserve un commit de merge que diga "aquí se cerró F12".

Entre el 08/08/2026 y el 22/09/2026 el repo suma 211 commits en main, 24 de ellos merges. No todos son cierres de fase: algunos son arreglos sueltos y un par, sincronizaciones con origin/main dentro de una rama. Aun así la lista de merges se lee como un índice del proyecto, de F1 a F13. Lo que no es una fase entera (documentación, guías, ajustes de instrucciones) va directo a main, sin ceremonia.

Requisito, ADR, tarea, código

El orden importa más que la rama. El ADR-010 (08/08/2026) fija esta cadena:

Requisito (E1) → Arquitectura (E2) → Decisión (ADR) → Tarea (TAREAS.md) → Código

Si algo no tiene requisito, primero lo escribo. Si el código y la especificación no coinciden, manda la especificación, y si estaba mal se cambia con fecha y motivo, no en silencio.

En el historial se ve: antes del código de F12 hay un commit con solo la especificación ("F12.1: especificacion aprobada por Jordi, con sus decisiones escritas"), y en F13 igual con /tools.

Casi todos los ADR llevan contexto, decisión, alternativas descartadas y consecuencias a favor y en contra; los más recientes añaden qué haría cambiar la decisión o cómo se comprueba que se cumple. Lo que más valor me da son las alternativas: dentro de dos meses no recordaré por qué no elegí la otra.

Y se enmiendan con fecha en lugar de reescribirse. El ADR-002 elegía LangGraph y PydanticAI, y dejaba escrito el plan B (pydantic a secas). El 02/09/2026 lo activé: PydanticAI no llegó a entrar en el proyecto. No porque se rompiera, sino porque había construido controles de seguridad en mi propio cliente de modelo y PydanticAI se los saltaría. La enmienda está debajo del texto original: se lee qué pensaba el 08/08 y por qué cambié el 02/09.

Lo que aprendí por las malas

29 commits que no existían en GitHub

Entre el 15/08 y el 01/09 hubo 29 commits, con F1 entera dentro, que no estaban en GitHub: el push era un paso aparte y dependía de mí. Lo descubrí al copiar el proyecto a un segundo portátil, que no tenía nada de lo construido desde el 20/08.

No se perdió trabajo: estaba en el .git local. Pero un commit que solo existe en una máquina está a un disco duro de desaparecer. De ahí salieron las normas actuales, escritas en el propio proyecto:

  • Cada commit se empuja a origin en el mismo turno en que se hace.
  • No se reescribe historial ya publicado.
  • No se usa push --force.
  • No se borra una rama sin que yo lo pida en ese momento.

Autorizar el ciclo normal no autoriza lo irreversible.

Cuatro repos, cuatro maneras de trabajar

No todos mis proyectos funcionan igual:

RepoFlujoMensajes de commitAutomatización
agente-telegramRama por fase, merge --no-ffPrefijo FN.M: en 94 de 187 commits sin contar mergesArnés de pruebas en cada tarea
multi-agenteMerges a main desde ramas de trabajoConventional Commits en 75 de 82 commits sin mergeCI, escaneo de secretos, Dependabot semanal
tutor-clinicoCommits pequeños sobre mainConventional Commits en 59 de 60 commits sin mergeCI con make check y hooks pre-commit
pullsightGitFlow en equipoPull requests hasta el #74CODEOWNERS

En multi-agente hay un tag v1.0.0 y Dependabot revisa cada lunes a las 09:00 pip y las GitHub Actions. La entrada de Actions existe porque estaban fijadas a un SHA, lo cual es correcto, pero sin Dependabot quedaban congeladas para siempre. El historial también conserva el merge de cierre de una rama de auditoría de seguridad (hardening/auditoria-seg) con sus correcciones.

En tutor-clinico (el repo se llama mis-especialistas) los hooks pre-commit impiden commitear un .env (salvo .env.example), la carpeta .privado/ o ficheros .pem y .key. Es un error que no quiero poder cometer:

- id: forbid-env-files
  stages: [pre-commit, manual]
  name: no commitear .env (usa .env.example)
  language: fail
  entry: ".env contiene secretos: nunca se commitea. La plantilla es .env.example."
  files: '(^|/)\.env(\..+)?$'
  exclude: '(^|/)\.env\.example$'

Su CHANGELOG sigue Keep a Changelog: cada entrada cuenta qué cambia para quien opera el sistema, no cada commit, porque para eso está git log.

Trabajar en equipo: pullsight

En pullsight trabajé con otras personas, con una variante de GitFlow: develop como rama por defecto, ramas feature por tarea (algunas con número de issue, como feature/21-... y feature/35-...) y pull requests hasta el #74. No vi ramas de release. El CODEOWNERS tiene una sola línea que asigna todo el repositorio a una persona.

En pullsight aprendí a coordinar ramas, issues y pull requests con otras personas, algo que en un proyecto propio no te enseña nadie: ahí la disciplina depende de que varias personas se pongan de acuerdo.

Una anécdota de .gitignore

Mi vault de notas tiene un .gitignore con una negación que parece rara:

!08-GUIAS/auditoria-seguridad-guia-completa.md

Mi ~/.gitignore_global tiene la regla AUDITORIA-SEGURIDAD-*.md para no versionar los informes de mi skill de auditoría. Pero Windows no distingue mayúsculas, y esa regla se tragaba también una guía del vault que sí quería versionar. La negación la rescata, porque el .gitignore del repo tiene prioridad sobre el global. Lo dejé comentado para que nadie la borre por "limpiar".

Compartir