Opened 9 days ago
Last modified 8 days ago
#36166 new Bug
Backwards migration to replaced migration leads to InconsistentMigrationHistory on forward migrate
Reported by: | Klaas van Schelven | Owned by: | |
---|---|---|---|
Component: | Migrations | Version: | 5.1 |
Severity: | Normal | Keywords: | |
Cc: | Jacob Walls | Triage Stage: | Accepted |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
When squashing migrations, migrating back is broken when referencing a now-replaced migration.
I have migrations as such:
- 0001_initial.py
- 0002_foomodel_bar.py
- 0001_squashed_0002_foomodel_bar.py squashing 0001 & 0002
- 0003_foomodel_after_squash.py depending on the squashed migration (Django does this by default when making a new migration after squashing, and it's the right thing)
However, after migrating fully, migrating back to the last replaced migration does not actually undo 0003.
$ python manage.py migrate squashme Operations to perform: Apply all migrations: squashme Running migrations: Applying squashme.0001_squashed_0002_foomodel_bar... OK Applying squashme.0003_foomodel_after_squash... OK $ python manage.py migrate squashme 0002 Operations to perform: Target specific migration: 0002_foomodel_bar, from squashme Running migrations: No migrations to apply. (freshdjango) klaas@pop-os:~/dev/squashtest$ python manage.py migrate squashme Operations to perform: Apply all migrations: squashme Running migrations: No migrations to apply.
Migrating even further back into that chain leads to inconsistent migration history:
(freshdjango) python manage.py migrate squashme Operations to perform: Apply all migrations: squashme Running migrations: Applying squashme.0001_squashed_0002_foomodel_bar... OK Applying squashme.0003_foomodel_after_squash... OK (freshdjango) klaas@pop-os:~/dev/squashtest$ python manage.py migrate squashme 0001_initial Operations to perform: Target specific migration: 0001_initial, from squashme Running migrations: Rendering model states... DONE <= shouldn't there be undoing of 0003? Unapplying squashme.0002_foomodel_bar... OK (freshdjango) klaas@pop-os:~/dev/squashtest$ python manage.py migrate squashme Traceback (most recent call last): [..] raise InconsistentMigrationHistory( django.db.migrations.exceptions.InconsistentMigrationHistory: Migration squashme.0003_foomodel_after_squash is applied before its dependency squashme.0002_foomodel_bar on database 'default'.
Migrating back to the squashing migration instead (if you didn't do the above) does what you'd expect:
(freshdjango) python manage.py migrate squashme 0001_squashed_0002_foomodel_bar Operations to perform: Target specific migration: 0001_squashed_0002_foomodel_bar, from squashme Running migrations: Rendering model states... DONE Unapplying squashme.0003_foomodel_after_squash... OK
Change History (3)
comment:1 by , 8 days ago
Summary: | squashmigrations breaks backward migration detection → Backwards migration to replaced migration leads to InconsistentMigrationHistory on forward migrate |
---|---|
Triage Stage: | Unreviewed → Accepted |
comment:2 by , 8 days ago
it would be named 0001_initial_squashed_0002_foomodel_bar.py
Not in my world (Django 5.1):
(freshdjango) $ python manage.py squashmigrations squashme 0002 Will squash the following migrations: - 0001_initial - 0002_foomodel_bar Do you wish to proceed? [y/N] y Optimizing... Optimized from 2 operations to 1 operations. Created new squashed migration /mnt/datacrypt/dev/squashtest/squashme/migrations/0001_squashed_0002_foomodel_bar.py You should commit this migration but leave the old ones in place; the new migration will be used for new installs. Once you are sure all instances of the codebase have applied the migrations you squashed, you can delete them.
When it had the original name
I'm not sure that line of reasoning matters much to the present discussion, it's more of a separate annoyance that makes it inconvenient (impossible even) to specify a specific migration when the full name of one is the prefix of another... :-D
I'm not sure it makes sense to migrate backwards to replaced migrations (and we could error instead of allowing it)
I'm not sure either... but:
Possibly related: #24900
"Allowed migrating backward to squashed migrations" is the name of the PR, so it seems this is indeed the ambition
comment:3 by , 8 days ago
Cc: | added |
---|
Not in my world (Django 5.1):
Ah apologies, I had ran python manage.py squashmigrations squashme 0001 0002
which had the different name. Replicated
I'm not sure that line of reasoning matters much to the present discussion
I was thinking that there were additional manual steps here (which I believe would be relevant as it would reduce the likelihood of someone encountering the error), but the commands being ran to create the migration were different.
cc-ing Jacob as he was involved in that PR
Note the commentary of #36168 might be useful to this ticket
Note that if you were to recreate the squashed migration, it would be named
0001_initial_squashed_0002_foomodel_bar.py
but it appears the file and dependency was renamed to0001_squashed_0002_foomodel_bar.py
.When it had the original name, we do not hit the
InconsistentMigrationHistory
error because doingpython manage.py migrate squashme 0001_initial
gives:CommandError: More than one migration matches '0001_initial' in app 'squashme'. Please be more specific.
Note that doing
python manage.py migrate squashme zero
and then migrate still un-applies and applies the migration correctly (this is also true with the renamed migration)I'm not sure it makes sense to migrate backwards to replaced migrations (and we could error instead of allowing it)
Replicated on 5.1 and main. Thank you for the ticket and project 👍
Possibly related #24900