Saltar al contenido principal

Wiedii — Política de Branching con Git Flow

⚠️ Verificar versiones antes de usar — la versión de git-flow-next documentada aquí puede estar desactualizada. Consultar brew info git-flow-next o git-flow.sh para la versión más reciente. Ver politicas-core.

Se usa git-flow-next; el preset depende del flujo del proyecto — --preset=classic para Git Flow (crea main + develop con los prefijos feature/, release/, hotfix/, support/) y --preset=github para repos de solo main (activa únicamente main + feature).

Instalación: brew install git-flow-next

Cuándo Git Flow vs GitHub Flow (excepción general)

Git Flow es el default en Wiedii, pero su rama develop solo aporta valor si el proyecto cumple al menos uno de estos criterios. Si no cumple ninguno, la rama de integración es ceremonia sin beneficio y se recomienda GitHub Flow (solo main).

Criterios que justifican Git Flow (mantener develop):

CriterioQué problema resuelve develop
Software versionado que terceros consumen fijando versión (librerías, SDKs, CLIs, paquetes publicados)Separa "lo ya liberado" de "lo que viene"
Se soportan varias versiones en producción simultáneamenteHabilita hotfix/* y support/* sobre versiones viejas
Releases agrupadas con ventana de estabilizaciónrelease/* estabiliza antes de taggear
Existe un entorno de staging/preview mapeado a developPermite ver/QA los cambios antes de prod

Cuándo se recomienda GitHub Flow (solo main):

Cuando el proyecto reúne este perfil (típico de sitios estáticos, wikis, apps internas, servicios con despliegue continuo):

  • Un solo entorno de despliegue (una sola producción; sin staging atado a develop).
  • Despliegue continuo: cada merge a main —o cada tag sobre main— va a producción.
  • Sin fijado de versión por consumidores (nadie hace pin a proyecto@1.2.0).
  • La madurez del contenido/cambios está gobernada aguas arriba (p. ej. el ciclo borrador → maduro → promovido del vault), no por la topología de ramas.
  • Cambios de bajo riesgo, corregibles hacia adelante (fix-forward).

Modelo GitHub Flow en Wiedii

main ← siempre desplegable; única rama de larga vida
feature/* ← ramas cortas desde main (features y fixes)

No se usa fix/*. GitHub Flow no prescribe prefijos (son ramas descriptivas desde main), y fix/ no es una rama de Git Flow (los arreglos van por hotfix/ o feature/). Además, el preset github de git-flow-next solo activa main + feature, así que no existe git flow fix. En Wiedii se usa feature/* para todo —features y fixes— para no romper el flujo git flow uniforme. (No confundir con el tipo de commit Conventional fix:, que sí aplica y es cosa aparte.)

Inicialización (una vez por clon): git flow init --preset=github — el preset github de git-flow-next activa solo main + feature, frente a classic que crea también develop y los prefijos de release/hotfix.

# Flujo de feature en GitHub Flow (mismos comandos git flow; destino main)
git switch main && git pull --ff-only origin main
git flow feature start 0001-slug
wietoo commit # wietoo → Conventional Commits + closed #<id>
git flow publish -o merge_request.create \
-o merge_request.target=main \
-o "merge_request.title=feat(scope): description [#0001]"
# Release: taggear main directamente (los tags y SemVer no cambian)
git switch main && git pull --ff-only
git tag -a 1.2.0 -m "Release 1.2.0" && git push origin 1.2.0

⚠️ GitHub Flow cambia la topología de ramas, NO las reglas core. Siguen vigentes sin excepción: MR obligatorio, nadie mergea su propio MR, main protegida, rebase antes de merge, merge.ff=false, Conventional Commits con closed #<id>, tags sin prefijo v.

Requisitos para adoptar GitHub Flow

  1. Documentar la excepción en el repo (CLAUDE.md / CONTRIBUTING.md) y, como altera la relación con el estándar, validarla con quien gobierna las políticas Wiedii — no un drift tácito.
  2. Renovate: la rama por defecto del repo debe ser main y renovate.json debe llevar "baseBranchPatterns": ["main"] (ver renovate).
  3. Branch protection sobre main (push: solo mantenedores; merge: dev + mantenedores).

La política de Renovate ya contempla este perfil como "proyectos sin gestión de ramas" y lista documentación independiente como ejemplo: GitHub Flow no viola el estándar, es una ruta sancionada para los proyectos que encajan en el perfil de arriba.


Inicialización (una vez por clon del repo)

git flow init --preset=classic --defaults

# Wiedii: sin prefijo 'v' en los tags — sobreescribir inmediatamente después del init
git config gitflow.branch.release.tagprefix ""
git config gitflow.branch.hotfix.tagprefix ""

Sin este ajuste, el preset clásico establece tagprefix = v, generando v1.2.0 en lugar de 1.2.0. En Wiedii siempre se usa 1.2.0.

Esto crea: main (producción), develop (integración), con prefijos feature/, release/, hotfix/, support/.

Reglas de ramas

RamaPropósitoOrigenSe fusiona en
mainProducción — siempre desplegable
developBase de integraciónmain
feature/*Nueva funcionalidaddevelopdevelop (via MR)
release/*Preparación de releasedevelopmain + develop (via MR)
hotfix/*Fix urgente en producciónmainmain + develop (via MR)
support/*Soporte de versiones legacymain

Push directo a main/develop: solo los mantenedores del proyecto (rol Maintainer en GitLab). El resto del equipo integra cambios siempre vía MR. Ver branch-protection.

Estrategia de merge

  • Actualizar rama desde su padre: git flow update — usa downstreamstrategy = rebase por defecto en el preset clásico (mantiene historia lineal)
  • Fusionar hacia el padre: siempre --no-ff (forzado globalmente por merge.ff=false)
  • Squash: NUNCA permitido
  • Borrar la rama de origen al fusionar el MR: el proyecto tiene activado delete source branch (remove_source_branch_after_merge), así que GitLab la borra al fusionar por la UI. Al fusionar por API/CLI hay que pedirlo explícito (glab mr merge --remove-source-branch, o la API con should_remove_source_branch=true) — no se aplica solo. Las ramas protegidas (main/develop) nunca se borran. Tras el merge, limpiar también la copia local de la rama (git branch -d <rama>).

Sincronizar local↔remoto sin merge commits espurios. Con merge.ff=false + pull.rebase=false globales (config git de Wiedii), un git pull normal crea un merge commit aunque el avance sea fast-forward. Para traer cambios limpio: git pull --ff-only (solo avanza si es FF, falla si divergió), o git fetch && git reset --hard origin/<rama> cuando local no tiene commits propios que conservar. Ver commits (config git de Wiedii).

Recomendación: integrar primero los MR más antiguos

Recomendación, no obligación. Cuando hay varios MR abiertos hacia la misma rama, conviene integrarlos del más antiguo al más nuevo según su fecha y hora de actualización completa (el updated_at del MR, con precisión de segundos — no solo el día), no la fecha de creación. Cada merge obliga a los demás MR a actualizarse sobre la nueva base; ir en ese orden reduce los rebases y conflictos repetidos y evita que un MR quede estancado acumulando divergencia.

Antes de mezclar cada MR, actualizar su rama con la rama por defecto del proyecto (develop, o main si ese es el default configurado) mediante rebasegit flow update o git rebase, nunca merge — para conservar la historia lineal (coherente con merge.ff=false y rebase antes del merge).

Aplica especialmente a los MR de Renovate: suele haber varios abiertos a la vez y Renovate rebasa automáticamente los que sigan abiertos cuando cambia la rama base. Integrar primero el de actualización más antigua deja que Renovate actualice o cierre el resto por sí solo, y mantiene las dependencias al día sin acumular MR viejos. Ver renovate-runner.

Conflictos en lockfiles (archivos de bloqueo)

Los lockfiles (bun.lock, go.sum, composer.lock, uv.lock, mise.lock) son autogeneradosnunca se editan a mano ni se resuelven sus conflictos en el editor. Se resuelve el conflicto en el manifiesto de dependencias y se deja que el comando de instalación regenere el lockfile coherente.

Procedimiento (cuando un rebase/merge marca conflicto en el lockfile):

  1. Resolver el conflicto en el manifiesto (no en el lockfile):

    StackManifiestoLockfileComando que lo regenera
    JS/TS (Bun)package.jsonbun.lockbun install
    Gogo.modgo.sumgo mod tidy
    PHP (Composer)composer.jsoncomposer.lockcomposer update --lock (o composer install si solo cambió el lock)
    Python (uv)pyproject.tomluv.lockuv lock (o uv sync)
    misemise.tomlmise.lockmise install (+ mise lock)
  2. Ejecutar el comando de instalación → regenera el lockfile sin conflictos.

  3. git add del manifiesto y del lockfile regenerado.

  4. Continuar: git rebase --continue (o cerrar el merge) y seguir el flujo de MR.

Por qué funciona: el lockfile es un derivado determinista del manifiesto; regenerarlo desde el manifiesto ya resuelto produce un lock correcto. Por eso el .gitattributes de Wiedii marca los lockfiles con -merge — git no inyecta marcadores <<<<<< ====== >>>>>> que corromperían el JSON/TOML. Ver cross-platform.

⚠️ El rebase del lado servidor de GitLab falla con lockfiles → rebasa en local. Es la consecuencia operativa del -merge: cuando un lockfile está en el diff, el botón "Rebase" del MR (y el auto-rebase de Renovate) no puede resolverlo en el servidor y reporta Rebase failed: Rebase locally.... Siempre que haya un lockfile en el diff, rebasa en local (con el procedimiento de arriba: rebase → regenerar el lock → git add--continue) y haz push — no uses el rebase del servidor.

Flujo de feature (paso a paso)

# 1. Partir desde develop actualizado
git switch develop && git pull origin develop
git flow feature start 0001-max-tres-palabras

# 2. Trabajar — commits atómicos
git add .
wietoo commit # wietoo → Conventional Commits + closed #<id>

# 3. Actualizar desde develop antes del MR (rebase via downstreamstrategy)
git flow update

# 4. Publicar la rama y abrir MR en un solo comando
git flow publish \
-o merge_request.create \
-o merge_request.target=develop \
-o "merge_request.title=feat(scope): description [#0001]"

NUNCA usar git flow feature finish — hace el merge localmente y saltea la protección de ramas y el CI.

Comandos cortos de git-flow-next

git-flow-next detecta automáticamente el tipo de rama actual:

git flow update # actualizar rama actual desde su padre (rebase)
git flow publish # hacer push de la rama actual al remoto
git flow finish # finalizar la rama actual (⚠️ evitar — usar flujo de MR)
git flow delete # eliminar la rama actual
git flow rename new-name # renombrar la rama actual
git flow overview # estado completo del repo: ramas, ahead/behind, health checks

Push options de GitLab para publish

git-flow-next pasa las opciones -o directamente a git push, que GitLab recibe como push options:

git flow publish -o merge_request.create # crear MR
git flow publish -o merge_request.target=develop # rama destino
git flow publish -o "merge_request.title=feat: ..." # título del MR
git flow publish -o merge_request.merge_when_pipeline_succeeds # auto-merge al pasar CI

Se pueden persistir en config para que git flow publish siempre cree el MR:

git config gitflow.feature.publish.push-option "merge_request.create"
git config --add gitflow.feature.publish.push-option "merge_request.target=develop"

Flujo de release

git flow release start 1.2.0 # sin prefijo v — nunca
# bump de versión en package.json, actualizar CHANGELOG
git flow publish \
-o merge_request.create \
-o merge_request.target=main \
-o "merge_request.title=chore(release): 1.2.0"

# Después de que el MR se fusione a main — tag y sync a develop:
git tag -a 1.2.0 -m "Release 1.2.0"
git push origin 1.2.0

glab mr create --source-branch release/1.2.0 --target-branch develop \
--title "chore: sync release/1.2.0 to develop"

Orden de MRs en un release

Los MRs incluidos en un release/* deben ordenarse ascendente por created_at (el más antiguo primero).

glab mr list --target-branch develop --state merged \
--output json | jq 'sort_by(.created_at)'

Las excepciones al orden (hotfix urgente, dependencia bloqueante, revert) deben quedar justificadas en el MR del release.

Flujo de hotfix

git switch main && git pull origin main
git flow hotfix start 1.2.1
wietoo commit # wietoo → Conventional Commits (type: fix) + closed #<id>

git flow publish \
-o merge_request.create \
-o merge_request.target=main \
-o "merge_request.title=fix: critical <description> [1.2.1]"

# Después de que el MR se fusione a main:
git tag -a 1.2.1 -m "Hotfix 1.2.1"
git push origin 1.2.1

# Sync a develop (CRÍTICO — si se omite, el bug vuelve en el siguiente release):
glab mr create --source-branch hotfix/1.2.1 --target-branch develop \
--title "chore: sync hotfix/1.2.1 to develop"

Template de MR (.gitlab/merge_request_templates/default.md)

Si el trabajo se asistió con IA, declarar herramienta + modelo (igual que el trailer Co-authored-by: de los commits — ver commits).

## What does this MR do?

## Why is it needed?

## How to test it?

## AI assistance
Tool(s) + model(s) used, if any — matches the `Co-authored-by` commit trailer
(e.g. Claude Code (claude-opus-4-6)). Write `None` if no AI was used.
Only whitelisted tools: Claude Code, Cowork.

## Checklist
- [ ] Tests passing
- [ ] Self-reviewed
- [ ] Docs updated if needed
- [ ] No critical/high security vulnerabilities
- [ ] AI assistance disclosed (tool + model) if used