skip to content

In a Django team, when would you renumber one of two conflicting 0042 migrations onto the other instead of committing a merge migration?

level: seniorimportance: should knowfreq 30%

answer

  1. linear history versus a fork
  2. what django_migrations stores
  3. has it run anywhere shared?
  4. the renamed file looks new

basics

~20 s

Renumber, making one migration 0043 that depends on the other 0042, when it has only run on disposable local databases; history stays linear. Once both ran on shared databases, merge instead: a renamed file looks unapplied and Django would run it again.

solid answer

~40 s

Both approaches fix two leaf nodes. **Renumbering** rewrites one branch's migration so it becomes `0043_order_gift_note` depending on `0042_order_coupon_code`: history stays linear and no merge file accumulates. But Django records applied migrations in `django_migrations` by app and full name, so any database that already ran `0042_order_gift_note` sees `0043_order_gift_note` as new and re-runs its `AddField`, which fails on the existing column. So I renumber only while the migration has run nowhere but local databases I can reset, typically before the pull request merges. Once it has reached staging or production, I use `makemigrations --merge`. If a renamed migration did reach some databases, they need their records fixed, and `migrate --prune` removes rows for files that no longer exist.

go deeper

for a junior

Know that django_migrations stores each applied migration by app and name, so renaming a migration makes it look new.

for a middle

Explain both resolutions and the regenerate-on-rebase workflow, including rolling the local database back first.

for a senior

Judge per migration whether it has run anywhere shared, and know how to repair records on a database that ran a renamed migration.

for a principal

Set a team rule, such as rebase-before-merge plus merge-once-shared, and a CI check that forces the decision into the pull request.

## Two ways to rejoin a forked graph When two branches each add a migration to the same app from the same parent, the app has two **leaf nodes** and `migrate` refuses to run. There are two standard resolutions. | | Merge migration | Renumbering (rebasing) | |---|---|---| | What changes | a new `0043_merge_...` file with two dependencies | one branch's file renamed and its dependency changed | | History shape | a diamond: fork plus join | a straight line | | Existing records | untouched; both names stay valid | the old name disappears from disk | | Safe when | always, if operations do not overlap | the migration has not run on any database you keep | | Leaves behind | an extra empty file | nothing | ## Why the migration's name is its identity The `django_migrations` table stores one row per applied migration, keyed by **app label and migration name**. The number is part of the name. Rename `0042_order_gift_note` to `0043_order_gift_note` and, to Django, it is a brand-new, unapplied migration: 1. A database that already ran the old file has a row for `0042_order_gift_note` and none for `0043_order_gift_note`. 2. `migrate` tries to apply `0043_order_gift_note` and runs `AddField` for `gift_note` again. 3. The database rejects it because the column already exists. 4. Meanwhile the old row points at a file that no longer exists on disk. That is why renumbering is a pre-merge operation, not a post-deploy one. ## Renumbering step by step 1. Rebase or merge the other branch into yours so its `0042_order_coupon_code` is present. 2. Roll your local database back to before your migration (`migrate orders 0041`), or plan to recreate it. 3. Delete your `0042_order_gift_note.py` and run `makemigrations orders` again; Django generates `0043_...` depending on the other branch's 0042. Regenerating is simpler and safer than hand-editing the number and `dependencies`. 4. Check that no migration in another app depends on the old name; update it if one does. 5. Migrate forward and run `makemigrations --check`. ## Cleaning up if a renamed migration escaped - On a database that ran the old name, the schema is already correct, so the new name must be **recorded as applied without running**; the tool for that is `migrate --fake` for that migration. - `migrate --prune` deletes `django_migrations` rows whose files no longer exist, removing the stale old name. - Do this deliberately per database; getting it wrong leaves schema and records out of step. ## Choosing a team policy - **Rebase-before-merge**: authors regenerate their migration on top of main before merging, so main stays linear and merge files are rare. - **Merge when shared**: once a migration has been deployed to any long-lived environment, never rename it; use `makemigrations --merge` if a fork appears. - **CI guard**: `makemigrations --check` fails on a forked graph, so the rebase-or-merge decision happens in the pull request. - **Periodic squashing** later folds accumulated merge files into a clean history. The rule of thumb interviewers listen for: renumber what only you have applied; merge what anybody else has applied.

  • Why is regenerating with makemigrations usually better than editing the number by hand?
    Regenerating recomputes the dependency and the operations against the other branch's final state. If both branches touched the same model, the regenerated migration expresses the correct final definition, whereas a hand-renamed file keeps operations written against the old parent.
  • What does migrate --prune do, and when is it needed?
    It deletes rows from `django_migrations` whose migration files no longer exist on disk, for one app. It is useful after a renamed or deleted migration left a stale record, and after deleting files a squashed migration replaced, so the table matches the code.

saying these in an interview costs you the question

  • Numbers are only labels, so renaming an applied migration is harmless
  • Django matches applied migrations by their operations, not their names
  • Renumbering is fine after deploy if the operations are unchanged
  • Merge migrations should always be avoided by renaming files
  • Migrations in different apps can conflict with each other's leaves