Git para Trabajo con Bases de Datos
El control de versiones para un cambio de esquema no es exactamente lo mismo que el control de versiones para el código de la aplicación, porque un archivo de migración fusionado describe un cambio en un sistema con estado que git en sí mismo no puede revertir.
Esta página construye el modelo mental para esa diferencia en los equipos de PostgreSQL 18.4: por qué existen dos registros separados, cómo se mantienen reconciliados y por qué esa reconciliación impulsa casi todas las convenciones de git que adopta un equipo de bases de datos.
Resumen
- Git y la base de datos mantienen cada uno su propio registro del historial de esquemas, y toda la disciplina de "git para trabajo con bases de datos" consiste en mantener esos dos registros reconciliados.
- Por Qué Importa: Un archivo de migración, a diferencia de un cambio de código de aplicación, ya ha tenido un efecto secundario irreversible en un sistema en vivo en el momento en que se fusiona y se ejecuta.
- Conceptos Clave: doble registro, inmutabilidad de migraciones, orden de despliegue, expandir-contraer, detección de deriva.
- Cuándo Usar: Utiliza este modelo siempre que estés diseñando políticas de ramas, escribiendo una plantilla de PR o depurando por qué los esquemas de staging y producción no coinciden.
- Limitaciones / Compensaciones: Ninguna cantidad de disciplina de git sustituye a un simulacro de restauración real, ya que git solo demuestra que la intención se registró, no que el cambio sea seguro.
- Temas Relacionados: revisión de código para SQL, patrón expandir-contraer, ejecutores de migraciones.
Fundamentos
Cada equipo que realiza trabajo de esquemas mantiene en realidad dos registros de historial diferentes al mismo tiempo.
El primer registro es git, que registra la intención de cambiar el esquema como una secuencia de commits revisada y ordenada.
El segundo registro es la propia tabla de historial de migraciones de la base de datos ( flyway_schema_history o su equivalente en Liquibase), que registra lo que se ha aplicado realmente, y en qué orden, en cada entorno específico.
Estos dos registros coinciden cuando cada entorno ha ejecutado todas las migraciones que git ha fusionado, en el mismo orden, y discrepan en el momento en que alguien ejecuta SQL manualmente fuera de ese proceso.
Una analogía útil es un manifiesto de envío frente al inventario físico de un almacén: el manifiesto dice lo que debería estar allí, el almacén dice lo que realmente hay, y una discrepancia entre ellos es donde residen los incidentes.
Dado que una migración cambia el estado en vivo en el instante en que se ejecuta, un archivo de migración fusionado se trata como efectivamente inmutable: la solución a un error es siempre una nueva migración hacia adelante, nunca una edición del historial que otros entornos ya hayan aplicado.
Este es el mayor cambio mental respecto a los hábitos de git con código de aplicación, donde modificar o reescribir un commit reciente es rutinario y en su mayoría inofensivo.
Mecánicas e Interacciones
La reconciliación entre los dos registros es lo que da forma a casi todas las convenciones en esta sección, comenzando con la política de ramas.
main se mantiene "siempre migratable", lo que significa que cada migración fusionada allí ya ha pasado en staging, por lo que una migración rota en main se trata como un incidente que bloquea el despliegue en lugar de un error normal.
El orden de despliegue es una consecuencia directa del modelo de doble registro: la migración debe aplicarse antes de que se envíe el código de la aplicación que depende de la nueva columna o tabla, o la aplicación en ejecución consultará un esquema que aún no existe.
El patrón expandir-contraer existe específicamente porque los commits de git y un cambio de esquema en vivo nunca pueden aterrizar atómicamente juntos: expandir agrega la nueva forma mientras la antigua aún funciona, y contraer elimina la antigua solo después de que todos los consumidores se hayan movido.
La revisión de código en un PR de migración tiene más peso que la revisión en un PR de código de aplicación típico, porque el revisor es el último punto de control antes de que un cambio con efectos secundarios reales llegue a un sistema en vivo.
La detección de deriva (comparar la tabla de historial de migraciones entre entornos) es el mecanismo que detecta el momento en que alguien omite git y ejecuta SQL directamente contra una base de datos.
El fragmento a continuación es el tipo de consulta que un revisor ejecuta para confirmar que los dos registros aún coinciden antes de aprobar la siguiente migración en secuencia.
SELECT installed_rank, version, description, success
FROM flyway_schema_history
ORDER BY installed_rank DESC
LIMIT 5;Si la fila más reciente en producción no coincide con lo que git dice que fue la última fusionada, los dos registros ya se han desviado.
Consideraciones Avanzadas y Aplicaciones
A escala, el modelo de doble registro tiene que responder a una pregunta que el código de aplicación git rara vez enfrenta: ¿quién posee el próximo número de versión cuando hay varios PR en vuelo a la vez?
Un monorepo de esquema compartido típicamente asigna a un DBA de plataforma o a un bot automatizado la tarea de asignar la próxima versión de migración, precisamente para evitar que dos PR colisionen en el mismo espacio.
Las arquitecturas de base de datos por servicio evitan esa colisión por completo al dar a cada servicio su propia secuencia de migración, a costa de perder una vista única y global del clúster del historial de esquemas.
El "squashing" (compresión) del historial es seguro para las líneas base preproducción, pero peligroso a partir de ese punto, porque comprimir después de que una migración ya se ha aplicado en cualquier entorno real rompe la suma de verificación que el ejecutor de migraciones utiliza para detectar manipulaciones.
Los hotfixes de emergencia complican aún más el modelo: un operador que ejecuta SQL manualmente a las 3 a.m. para detener una interrupción está, por definición, rompiendo la reconciliación del doble registro, por lo que la convención es confirmar ese mismo SQL como una migración adecuada en cuestión de horas, no días.
A medida que los equipos maduran, el flujo de trabajo de git en sí mismo se convierte en la pista de auditoría en la que confían los reguladores y los revisores de seguridad, ya que vincula cada declaración DDL a un ticket, un autor y un revisor de una manera que una sesión de shell de producción ad hoc nunca puede hacerlo.
| Enfoque | Fortaleza | Debilidad | Mejor Ajuste |
|---|---|---|---|
| Migraciones solo hacia adelante con SQL de reversión documentado | Modelo mental simple, el historial de git se mantiene lineal | El SQL de reversión se escribe pero rara vez se ensaya hasta que se necesita | La mayoría de los equipos de aplicaciones que envían incrementalmente |
| Reversiones aplicadas automáticamente | La reversión es un solo comando | Los scripts de reversión se desvían de la realidad tan fácilmente como los de avance, y rara vez se prueban | Equipos con fuerte disciplina de CI que imponen pruebas de reversión |
| DDL manual en producción, confirmado después del hecho | Respuesta más rápida durante un incidente en vivo | Los registros están desincronizados hasta que llega el commit, y esa ventana es un riesgo real | Solo para emergencias, nunca como práctica habitual |
Conceptos Erróneos Comunes
- "Un PR de migración se puede modificar o reescribir como código normal" - una vez que cualquier entorno lo ha aplicado, editar el archivo rompe la verificación de suma de verificación en todos los entornos que ya ejecutaron la versión anterior.
- "El historial de git por sí solo demuestra lo que está en producción" - solo la propia tabla de historial de migraciones de la base de datos demuestra lo que se ha aplicado realmente; git solo demuestra lo que se pretendía.
- "Comprimir commits siempre es una limpieza segura" - comprimir es seguro antes de que producción haya aplicado esas migraciones, e inseguro después, porque reescribe el historial del que depende el ejecutor de migraciones.
- "SQL de reversión significa que siempre puedes revertir limpiamente" - una migración descendente documentada es un mejor esfuerzo, no una garantía, especialmente una vez que se han escrito datos contra la nueva forma.
- "El orden de despliegue de la aplicación y el despliegue de la migración no importan realmente" - desplegar código de aplicación antes de su migración es una de las causas más comunes de una interrupción en producción en flujos de trabajo de cambio de esquema.
Preguntas Frecuentes
¿Por qué el trabajo de base de datos necesita una disciplina de git diferente a la del código de aplicación?
Porque una migración fusionada ya ha tenido un efecto secundario irreversible en un sistema en vivo en el momento en que se ejecuta, a diferencia de un despliegue de código de aplicación que generalmente se puede revertir.
¿A qué se refieren los "dos registros" de esta página?
- Git, que registra la intención revisada de cambiar el esquema.
- La propia tabla de historial de migraciones de la base de datos, que registra lo que se ha aplicado realmente en cada entorno.
¿Puedo editar un archivo de migración después de que se haya fusionado?
No una vez que cualquier entorno lo haya aplicado: la solución segura es siempre una nueva migración hacia adelante, ya que la edición rompe la verificación de suma de verificación en otros lugares.
¿Por qué el orden de despliegue importa tanto para los cambios de base de datos?
Porque el código de aplicación que asume que una nueva columna o tabla existe fallará si se despliega antes de que la migración que la crea se haya ejecutado realmente.
¿Qué es expandir-contraer, conceptualmente?
Un patrón para cambiar el esquema en dos pasos seguros: agregar la nueva forma mientras la antigua aún funciona, luego eliminar la antigua solo después de que todos los consumidores se hayan movido, porque git y un esquema en vivo no pueden cambiar atómicamente juntos.
¿Quién debe poseer el próximo número de versión de migración en un esquema compartido?
Generalmente un DBA de plataforma o un asignador automatizado, específicamente para evitar que dos PR en vuelo colisionen en el mismo espacio de versión.
¿Está bien ejecutar SQL directamente en producción fuera de git?
Solo como una medida de emergencia genuina, e incluso entonces el mismo SQL debe confirmarse como una migración adecuada en cuestión de horas para restaurar la reconciliación del registro.
¿Cuándo es seguro comprimir commits de migración?
Solo antes de que cualquier entorno real haya aplicado esas migraciones; comprimir después de ese punto rompe la suma de verificación en la que se basa el ejecutor de migraciones.
¿Importa más la política de migraciones solo hacia adelante o de reversión que elegir una?
La consistencia importa más que la elección específica: lo que rompe a los equipos es cambiar las políticas a mitad de proyecto sin actualizar las suposiciones de cada migración existente.
¿Cómo se detecta que los dos registros se han desviado?
Comparando la versión aplicada más reciente de la tabla de historial de migraciones con lo que git dice que fue la última fusionada en esa rama.
¿Por qué la revisión de código importa más para un PR de migración que para un PR de aplicación típico?
Porque el revisor es el último punto de control antes de que un cambio con efectos secundarios reales, a menudo irreversibles, llegue a un sistema en vivo.
¿Cambia una arquitectura de base de datos por servicio este modelo?
Elimina el problema de colisión de versiones al dar a cada servicio su propia secuencia, a costa de una vista única y global del clúster del historial de esquemas.
Relacionados
- Fundamentos de Git para Trabajo con Bases de Datos - la estructura de carpetas concreta y el flujo de trabajo de PR que este modelo sustenta.
- Revisión de Código para SQL - la lista de verificación de revisión que aplica la disciplina de reconciliación de registros de esta página.
- Fundamentos de Migraciones - las mecánicas del ejecutor de migraciones referenciadas en toda la página.
- DDL sin tiempo de inactividad - el patrón expandir-contraer en la práctica.
- Habilidad de Seguridad de Migraciones - una habilidad de agente que califica las preocupaciones de riesgo de bloqueo de esta página.
Versiones de Stack: Esta página es conceptual y está dirigida a equipos de PostgreSQL 18.4; las versiones específicas de los ejecutores de migraciones (Flyway, Liquibase) se cubren en sus páginas dedicadas en la sección migrations-schema-change.