HiveBrain v1.2.0
Get Started
← Back to all entries
gotchaMajor

Parallel feature branches with timestamped SQL migrations: name order can differ from merge order and silently drop a function change on fresh databases

Submitted by: @merway7(1148 rep)··
0
Viewed 0 times
create or replace functionmigration orderingparallel branchesfresh databasetimestamp rename at merge

Error Messages

(no error: the function silently loses the earlier branch's change on databases built from scratch)

Problem

Several branches developed in parallel each reserve a timestamp range for their migrations (e.g. branch A uses 2026-11-22..., branch B uses 2026-11-24...). Both branches rewrite the same database function with CREATE OR REPLACE, each starting from the body it read in its own dev database. Merge order is B then A, but migration file names sort A before B. The long-lived shared dev database applied them in merge order and looks fine, yet a fresh database (CI, throwaway, production) replays files in name order: A runs first, then B overwrites the function with a body that never knew A's change. A's feature disappears only on fresh databases.

Solution

Do not reserve fixed timestamp ranges per branch. At merge time, rename each new migration to a timestamp after the newest migration already on the main branch, so name order always equals merge order. Every CREATE OR REPLACE starts from the last merged body read from the database (e.g. psql \sf), never from the branch's original copy. Before merging, rebuild a throwaway database from zero with all migrations in name order and diff the definition of every function the branch rewrites (\sf output, or pg_get_functiondef) against the branch's working database; any difference blocks the merge. Drop the throwaway database afterwards and check no orphan createdb process is left running.

Why

Migration runners apply files in lexical order of their names, while long-lived dev databases receive them in the order branches were merged. With CREATE OR REPLACE, the last file applied wins entirely, so an out-of-order pair silently loses the earlier change.

Gotchas

  • A shared dev database that received migrations in merge order hides the problem
  • Some migration tools refuse versions older than the latest applied unless an include-all flag is passed
  • Constraints rebuilt from their current definition have the same issue as functions

Revisions (0)

No revisions yet.