Question

Have you ever encountered CommandError: Conflicting migrations detected; multiple leaf nodes in the migration graph:? You definetely have if you work on a team developing single django application.

How does it happen?

To understand the error, we need to analyze what Django does with migrations under the hood. Official Django Migration Documentation has in-depth explanation but long story short migrations remember ancestors and descendants and they have to be linearly ordered. There should not be a migration with multiple decendants that do not have child migrations (leaf nodes) in an app. This helps to rolback to any migration later on.

Example

Imagine you are in a team building Book Store website. You have books Django app and Book model inside it. Let’s say you are working on feature/book_isbn branch. You added isbn field to Book model and run python manage.py makemigrations. Meanwhile, your teammate is working on feature/book_cover_photo branch and added cover_photo field to Book model and a new migration for it.

To illustrate this have a look on this flowchart: Multiple leaf nodes

You both have common migration 0002_book_author but conflicting migration 0002_book_isbn and 0002_book_cover_photo respectively. When both branches are merged to develop and python manage.py migrate is run Bang! You get the CommandError: Conflicting migrations ...

Solution

Option 1

Django suggests to run python manage.py makemigration --merge to resolve it. This will create another migration that merges leaf migrations. makemigrations --merge Your migrations graph now looks like this: Multiple leaf nodes Run python manage.py migrate again and everything is fine, Yeeaah!

I personally don’t like having extra merge migration file. Also Django will probably not always merge migrations correctly. There has to be a better way.

Option 2

Checkout to develop branch that feature/book_isbn and feature/book_cover_photo merged in. Remove your migration file 0002_book_isbn from migrations folder. Rollback to the most recent common migration between the branches in this case 0002_book_author by running python manage.py books 0002_book_author. Now you can create a new migration for Book.isbn. Just run python manage.py makemigrations books again. You will have 0004_book_isbn migration like in flowchart below. Multiple leaf nodes

How to detect the conflict

Continious Integration at hand, we can check any migration conflicts and fail a build without stupidly trying to apply migrations to our database. This CLI command lists all conflicting migrations exist in the project. Run it from the root of your project. find . -type f -name "*.py"|grep -o ".*/migrations/[0-9]\+"|sort|uniq -c|awk '$1 > 1 {print $0}

Here is an example in Bitbucket-Piplines:


image: python:3.6

pipelines:
  default:
    ...
    - step:
        name: Apply migrations
        script:
          ...
          # Check any conflicting migrations, fail if so
          - CONFLICTING_MIGRATIONS=$(find . -type f -name "*.py" | grep -o ".*/migrations/[0-9]\+" | sort | uniq -c | awk '$1 > 1 {print $0}')
          - if [ -n "${CONFLICTING_MIGRATIONS}" ]; then echo "CONFLICTING MIGRATIONS:${CONFLICTING_MIGRATIONS}"; exit 1; fi;
          ...

You can put it in your CI pipeline like Jenkins, Travis etc.

In a nutshell

Django migrations are powerfull, magical tool to automate database operations. You have to know ins and outs of it. I hope you get something amazing from this post. Now go & build some cool Django apps.

Feedback & Comment

Your feedbacks and comments are most appreciated. Please write your opinion on this topic, share your experiance in the comment section below.