f0fa4315825 -> 3904558db1c6 (branchpoint),
let me substitute names that are more human friendly:
A -> B2
B1, B2, B3 -> C1
B1, B2, B3 -> C2
C1 -> D1 (head),
C2 -> D2 (head),
So I think, that's not all the history? Doesn't matter for the test
case I'm making so I assume it's something more like this:
A -> B1,
A -> B2,
A -> B3,
B1, B2, B3 -> C1
B1, B2, B3 -> C2
C1 -> D1 (head),
C2 -> D2 (head),
that is, you started with a single root, I'm assuming.
The steps to upgrade from A to D1/D2 come out normally:
upgrade a -> b3, b3
upgrade a -> b1, b1
upgrade a -> b2, b2
upgrade b1, b2, b3 -> c2, c2
upgrade c2 -> d2, d2
upgrade b1, b2, b3 -> c1, c1
upgrade c1 -> d1, d1
so those states have to be each represented in alembic_version
individually. Logging those transitions they come out as:
DEBUG:alembic.migration:update a to b3
DEBUG:alembic.migration:new branch insert b1
DEBUG:alembic.migration:new branch insert b2
DEBUG:alembic.migration:merge, delete ['b1', 'b2'], update b3 to c2
DEBUG:alembic.migration:update c2 to d2
where "update", "insert", and "delete" mean that's the SQL we're
going to run on alembic_version.
It then crashes on b1, b2, b3 -> c1, because it thinks it's
supposed to to an UPDATE, but there is no row to UPDATE because all
three of b1, b2, b3 are gone. What it really should do here is an
INSERT of c1. The logic that asks, "should we insert a row?"
looks to see if the revision (in this case c1) has multiple entries
as descendants, in which case it's a MERGE point, as c1 is. the
MERGE operation is currently coded in all cases to expect that when
we reach a MERGE point, all of its ancestors are definitely there,
else how else did we arrive at a MERGE point? But in this case
you've taken the same three revs and merged them twice, in effect
merged and branched at the same time. This was never expected.
The internal mechanics ask the question, "if we have more than one
anscestor, we're a MERGE point, therefore we definitely aren't
INSERTing an identifier". They also assert that, "if we have only
one anscestor, we're not a MERGE point, so if our ansestor *is* in
the current heads, we do an UPDATE and if it isn't, we do an
INSERT". The logic here can be simplified, such that, "if none
of our ancestors are in the current heads, we do an INSERT".
I've captured this all in
https://bitbucket.org/zzzeek/alembic/issue/297/transition-from-multiple-revs-to-one-as-a
where the logic has been opened up for mergepoints such that an
INSERT is considered to be OK under these conditions, that is in
c75be37640a19990d385a805 and will be out in 0.7.6.