Git para Trabalho com Banco de Dados
O controle de versão para uma alteração de esquema não é exatamente a mesma atividade que o controle de versão para código de aplicação, porque um arquivo de migração mesclado descreve uma alteração em um sistema com estado que o próprio git não pode reverter.
Esta página constrói o modelo mental para essa diferença em equipes PostgreSQL 18.4: por que dois registros separados existem, como eles permanecem reconciliados e por que essa reconciliação impulsiona quase todas as convenções de git que uma equipe de banco de dados adota.
Resumo
- Git e o banco de dados mantêm seus próprios registros do histórico de esquema, e toda a disciplina de "git para trabalho com banco de dados" é sobre manter esses dois registros reconciliados.
- Por que Importa: Um arquivo de migração, ao contrário de uma alteração de código de aplicação, já teve um efeito colateral irreversível em um sistema ativo no momento em que é mesclado e executado.
- Conceitos Chave: ledger duplo, imutabilidade de migração, ordenação de deploy, expandir-contrair, detecção de desvio.
- Quando Usar: Utilize este modelo sempre que estiver projetando política de branches, escrevendo um template de PR ou depurando por que os esquemas de staging e produção discordam.
- Limitações / Trade-offs: Nenhum nível de disciplina de git substitui um teste de restauração real, pois o git apenas prova que a intenção foi registrada, não que a alteração é segura.
- Tópicos Relacionados: revisão de código para SQL, padrão expandir-contrair, executores de migração.
Fundamentos
Toda equipe que realiza trabalho de esquema está, na verdade, mantendo dois registros de histórico separados ao mesmo tempo.
O primeiro registro é o git, que registra a intenção de alterar o esquema como uma sequência de commits revisada e ordenada.
O segundo registro é a tabela de histórico de migração do próprio banco de dados - flyway_schema_history ou seu equivalente no Liquibase - que registra o que foi realmente aplicado, e em que ordem, em cada ambiente específico.
Esses dois registros concordam quando cada ambiente executou todas as migrações que o git mesclou, na mesma ordem, e discordam no momento em que alguém executa SQL manualmente fora desse processo.
Uma analogia útil é um manifesto de remessa versus o inventário físico de um armazém: o manifesto diz o que deveria estar lá, o armazém diz o que realmente está, e uma incompatibilidade entre eles é onde os incidentes ocorrem.
Como uma migração altera o estado em tempo real no instante em que é executada, um arquivo de migração mesclado é tratado como efetivamente imutável - a correção para um erro é sempre uma nova migração forward, nunca uma edição do histórico que outros ambientes já aplicaram.
Esta é a maior mudança mental em relação aos hábitos de git de código de aplicação, onde alterar ou reescrever um commit recente é rotineiro e em grande parte inofensivo.
Mecânicas e Interações
A reconciliação entre os dois registros é o que molda quase todas as convenções nesta seção, começando pela política de branches.
main é mantido como "sempre migrável", o que significa que toda migração mesclada lá já passou no staging, então uma migração quebrada no main é tratada como um incidente que bloqueia o deploy, em vez de um bug normal.
A ordem de deploy é uma consequência direta do modelo de ledger duplo: a migração deve ser aplicada antes que o código da aplicação que depende da nova coluna ou tabela seja enviado, ou a aplicação em execução consultará um esquema que ainda não existe.
O padrão expandir-contrair existe especificamente porque commits de git e uma alteração de esquema em tempo real nunca podem ser lançados atomicamente juntos - expandir adiciona a nova forma enquanto a forma antiga ainda funciona, e contrair remove a forma antiga apenas depois que todos os consumidores se moveram.
A revisão de código em um PR de migração carrega mais peso do que a revisão em um código de aplicação típico, porque o revisor é o último ponto de verificação antes que uma alteração com efeitos colaterais reais atinja um sistema em tempo real.
A detecção de desvio - comparar a tabela de histórico de migração entre ambientes - é o mecanismo que captura o momento em que alguém ignora o git e executa SQL diretamente em um banco de dados.
O trecho abaixo é o tipo de consulta que um revisor executa para confirmar que os dois registros ainda concordam antes de aprovar a próxima migração em sequência.
SELECT installed_rank, version, description, success
FROM flyway_schema_history
ORDER BY installed_rank DESC
LIMIT 5;Se a linha mais recente na produção não corresponder ao que o git diz que foi mesclado por último, os dois registros já se desviaram.
Considerações Avançadas e Aplicações
Em escala, o modelo de ledger duplo precisa responder a uma pergunta que o git de código de aplicação raramente enfrenta: quem é o proprietário do próximo número de versão quando vários PRs estão em andamento ao mesmo tempo.
Um monorepo de esquema compartilhado geralmente atribui a um DBA de plataforma ou a um bot automatizado a alocação da próxima versão de migração, precisamente para evitar que dois PRs colidam no mesmo slot.
Arquiteturas de banco de dados por serviço evitam essa colisão inteiramente, dando a cada serviço sua própria sequência de migração, ao custo de perder uma visão única e clusterizada do histórico de migração.
Compactar o histórico é seguro para linhas de base pré-produção, mas perigoso após esse ponto, porque compactar depois que uma migração já foi aplicada em qualquer ambiente real quebra o checksum que o executor de migração usa para detectar adulteração.
Hotfixes de emergência complicam ainda mais o modelo: um operador executando SQL manualmente às 3 da manhã para interromper uma interrupção está, por definição, quebrando a reconciliação do ledger duplo, razão pela qual a convenção é registrar esse mesmo SQL como uma migração adequada em horas, não dias.
À medida que as equipes amadurecem, o próprio fluxo de trabalho do git se torna a trilha de auditoria em que reguladores e revisores de segurança realmente confiam, pois ele vincula cada instrução DDL a um ticket, um autor e um revisor de uma forma que uma sessão de shell ad hoc em produção nunca pode.
| Abordagem | Força | Fraqueza | Melhor Ajuste |
|---|---|---|---|
| Migrações apenas forward com SQL de rollback documentado | Modelo mental simples, histórico do git permanece linear | O SQL de rollback é escrito, mas raramente ensaiado até ser necessário | A maioria das equipes de aplicação enviando incrementalmente |
| Down migrations aplicadas automaticamente | Rollback é um único comando | Scripts de down migram da realidade tão facilmente quanto os forward, e raramente são testados | Equipes com forte disciplina de CI que impõem testes de down-migration |
| DDL manual de produção, commitado após o fato | Resposta mais rápida durante um incidente ao vivo | Ledgers ficam fora de sincronia até o commit chegar, e essa janela é um risco real | Apenas para emergências, nunca uma prática permanente |
Equívocos Comuns
- "Um PR de migração pode ser alterado ou reescrito como código normal" - uma vez que qualquer ambiente o aplicou, editar o arquivo quebra a verificação de checksum em todos os ambientes que já executaram a versão antiga.
- "O histórico do git sozinho prova o que está em produção" - apenas a tabela de histórico de migração do próprio banco de dados prova o que foi realmente aplicado; o git apenas prova o que foi pretendido.
- "Compactar commits é sempre uma limpeza segura" - compactar é seguro antes que a produção tenha aplicado essas migrações, e inseguro depois, porque reescreve o histórico do qual o executor de migração depende.
- "SQL de rollback significa que você sempre pode reverter de forma limpa" - uma migração down documentada é um melhor esforço, não uma garantia, especialmente depois que os dados foram escritos contra a nova forma.
- "A ordem de deploy da aplicação e o deploy da migração não importam realmente" - implantar código de aplicação antes de sua migração é uma das causas mais comuns de interrupção de produção em fluxos de trabalho de alteração de esquema.
FAQs
Por que o trabalho com banco de dados precisa de uma disciplina de git diferente do código da aplicação?
Porque uma migração mesclada já teve um efeito colateral irreversível em um sistema em tempo real no momento em que é executada, ao contrário de um deploy de código de aplicação que geralmente pode ser revertido.
Quais são os "dois registros" que esta página continua mencionando?
- Git, que registra a intenção revisada de alterar o esquema.
- A tabela de histórico de migração do próprio banco de dados, que registra o que foi realmente aplicado em cada ambiente.
Posso editar um arquivo de migração depois que ele for mesclado?
Não depois que qualquer ambiente o aplicou - a correção segura é sempre uma nova migração forward, pois editar quebra a verificação de checksum em outros lugares.
Por que a ordem de deploy é tão importante para alterações de banco de dados?
Porque o código da aplicação que assume que uma nova coluna ou tabela existe falhará se for implantado antes que a migração que a cria tenha sido realmente executada.
O que é expandir-contrair, conceitualmente?
Um padrão para alterar o esquema em duas etapas seguras - adicione a nova forma enquanto a antiga ainda funciona, então remova a forma antiga apenas depois que todos os consumidores se moveram - porque o git e um esquema em tempo real não podem mudar atomicamente juntos.
Quem deve ser o proprietário do próximo número de versão de migração em um esquema compartilhado?
Geralmente um DBA de plataforma ou um alocador automatizado, especificamente para evitar que dois PRs em andamento colidam no mesmo slot de versão.
É sempre aceitável executar SQL diretamente em produção fora do git?
Apenas como uma medida de emergência genuína, e mesmo assim o mesmo SQL deve ser registrado como uma migração adequada em horas para restaurar a reconciliação do ledger.
Quando é seguro compactar commits de migração?
Apenas antes que qualquer ambiente real tenha aplicado essas migrações - compactar após esse ponto quebra o checksum em que o executor de migração confia.
A política de migração forward-only ou down-migration importa mais do que escolher uma?
A consistência importa mais do que a escolha específica - o que quebra as equipes é mudar as políticas no meio do projeto sem atualizar as suposições de cada migração existente.
Como você detecta que os dois registros se desviaram?
Comparando a versão mais recente aplicada na tabela de histórico de migração com o que o git diz que foi mesclado por último naquele branch.
Por que a revisão de código é mais importante para um PR de migração do que para um PR de app típico?
Porque o revisor é o último ponto de verificação antes que uma alteração com efeitos colaterais reais e muitas vezes irreversíveis atinja um sistema em tempo real.
Uma arquitetura de banco de dados por serviço altera este modelo?
Remove o problema de colisão de versão ao dar a cada serviço sua própria sequência, ao custo de uma visão única e clusterizada do histórico de esquema.
Relacionados
- Noções Básicas de Git para Trabalho com Banco de Dados - a estrutura de pastas concreta e o fluxo de trabalho de PR que este modelo sustenta.
- Revisão de Código para SQL - a lista de verificação de revisão que impõe a disciplina de reconciliação de ledger desta página.
- Noções Básicas de Migrações - as mecânicas do executor de migração referenciadas em toda parte.
- DDL de Zero Downtime - o padrão expandir-contrair na prática.
- Skill de Segurança de Migração - uma skill de agente que pontua as preocupações de risco de bloqueio desta página.
Versões de Stack: Esta página é conceitual e visa equipes PostgreSQL 18.4; versões específicas de executores de migração (Flyway, Liquibase) são cobertas em suas páginas dedicadas na seção migrations-schema-change.