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-nexto 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):
| Criterio | Qué 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áneamente | Habilita hotfix/* y support/* sobre versiones viejas |
| Releases agrupadas con ventana de estabilización | release/* estabiliza antes de taggear |
Existe un entorno de staging/preview mapeado a develop | Permite 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 sobremain— va a producción. - Sin fijado de versión por consumidores (nadie hace
pinaproyecto@1.2.0). - La madurez del contenido/cambios está gobernada aguas arriba (p. ej. el ciclo
borrador → maduro → promovidodel 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 desdemain), yfix/no es una rama de Git Flow (los arreglos van porhotfix/ofeature/). Además, el presetgithubde git-flow-next solo activamain+feature, así que no existegit flow fix. En Wiedii se usafeature/*para todo —features y fixes— para no romper el flujogit flowuniforme. (No confundir con el tipo de commit Conventionalfix:, 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,
mainprotegida, rebase antes de merge,merge.ff=false, Conventional Commits conclosed #<id>, tags sin prefijov.
Requisitos para adoptar GitHub Flow
- 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. - Renovate: la rama por defecto del repo debe ser
mainyrenovate.jsondebe llevar"baseBranchPatterns": ["main"](ver renovate). - 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, generandov1.2.0en lugar de1.2.0. En Wiedii siempre se usa1.2.0.
Esto crea: main (producción), develop (integración), con prefijos feature/, release/, hotfix/, support/.
Reglas de ramas
| Rama | Propósito | Origen | Se fusiona en |
|---|---|---|---|
main | Producción — siempre desplegable | — | — |
develop | Base de integración | main | — |
feature/* | Nueva funcionalidad | develop | develop (via MR) |
release/* | Preparación de release | develop | main + develop (via MR) |
hotfix/* | Fix urgente en producción | main | main + develop (via MR) |
support/* | Soporte de versiones legacy | main | — |
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— usadownstreamstrategy = rebasepor defecto en el preset clásico (mantiene historia lineal) - Fusionar hacia el padre: siempre
--no-ff(forzado globalmente pormerge.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 conshould_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=falseglobales (config git de Wiedii), ungit pullnormal 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ó), ogit 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_atdel 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, omainsi ese es el default configurado) mediante rebase —git flow updateogit rebase, nunca merge — para conservar la historia lineal (coherente conmerge.ff=falsey 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 autogenerados — nunca 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):
-
Resolver el conflicto en el manifiesto (no en el lockfile):
Stack Manifiesto Lockfile Comando que lo regenera JS/TS (Bun) package.jsonbun.lockbun installGo go.modgo.sumgo mod tidyPHP (Composer) composer.jsoncomposer.lockcomposer update --lock(ocomposer installsi solo cambió el lock)Python (uv) pyproject.tomluv.lockuv lock(ouv sync)mise mise.tomlmise.lockmise install(+mise lock) -
Ejecutar el comando de instalación → regenera el lockfile sin conflictos.
-
git adddel manifiesto y del lockfile regenerado. -
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
.gitattributesde 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 reportaRebase 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