Teamwork and Migrations

If you work together with several people you get sooner or later conflicts because two developers create a new migration and there is a clash because both new migrations use the same number.

How do you handle this?

What do you do to avoid conflicts?

This exact problem is why I created django-linear-migrations, based on others’ work to solve the same problem. Check it out!

2 Likes

Wow, that looks great! Thank you.

I added your package to my django tips

I just thought I would offer my humble solution, but NB I will need to check Adam’s linear-migrations. (Adam, hi I just bought your book)

Pre-requisites: so far in our context, we have avoided needing data migrations, and have managed to operate with only the migrations generated from makemigrations. Its not that you can’t include data migrations, I just don’t know when / whether it would be hard.

Our approach is that migrations are tracked and committed, but we aim to be welcoming to beginners and able to include branches that have diverged totally from the ‘main’ branch (ie deleted the db and migrations and started over). This means that when we merge, we have to intervene (because git doesn’t provide tools for preserving a local version of a directory over a remote (ours vs theirs)). So we:

  1. merge with no-commit,
  2. delete all the migrations (which would now be a mess because git has just smashed the two trees of migrations together),
  3. git checkout migrations* and sqlite3 database that match from either of the branches (typically, the one with the most existing example data)
  • annoyingly, git checkout [hash] – /migrations/ works in Windows cmd but not in the Linux terminals I have used. In the Linux terminal, [app-folder]/migrations/* works; but when you have a lot of apps its a bit of a chore, so I use a script to crawl your project. This script would also enable a beginner to get their migrations and database back into a functional state, but I haven’t yet been able to apply it that way.
  1. to update the server, repeat these same steps, except you have to get the server migrations.

  2. run makemigrations and migrate

Below is the “invoke” script I use to get back the migrations from each folder for a chosen commit. If all migrations files were uniquely named, a script that looked in the database and pulled together copies of all the migrations that it records would work, but 0001_initial.py can be in the tree in a lot of different places with a lot of different stuff in it.

from invoke import task, run
@task(help={'hash': 'the commit you will recover migrations from'})
def getmigrations(ctx, hash):
    folders = [folder for folder in os.listdir() if os.path.isdir(folder)]
    for folder in folders:
        subfolders = [subfolder for subfolder in os.listdir(folder) if os.path.isdir(folder)]
        for subfolder in subfolders:
            if subfolder == 'migrations':
                print("attempting checkout {} -- {}/migrations/*".format(hash, folder))
                try:
                    run("git checkout {} -- {}/migrations/0*".format(hash, folder))
                except:
                    print("problem with checkout {} -- {}/migrations/*.py".format(hash, folder))
    migration_report = run("python manage.py showmigrations")
    print(migration_report.stdout)