bigywater.tech
Django · 57

Migration 冲突与合并

团队并行开发时最常见的迁移问题:两个人各生成了 0002。Django 怎么发现的,merge 到底做了什么,它能保证合并后正确吗?这篇复现冲突,并故意制造一个「合并后仍然冲突」的例子。

两个叶子节点
同一个 app 出现两个叶子迁移时,migrate 与 makemigrations 都拒绝运行
空操作
--merge 生成的迁移 operations 为空,只把两条依赖线接起来
不检查兼容
两个分支给同一字段加不同类型,SQLite 悄悄成功,PostgreSQL 报错

冲突的样子

实测 · 本机执行输出
  migrate → To fix them run 'python manage.py makemigrations --merge'
  makemigrations → To fix them run 'python manage.py makemigrations --merge'
  showmigrations lab:
    lab
     [X] 0001_initial
     [ ] 0002_add_a
     [ ] 0002_add_b

迁移之间的依赖是图,同一个 app 有两个「没有后继」的迁移就是分叉。

makemigrations --merge

实测 · 本机执行输出
  Merging lab
    Branch 0002_add_a
      + Add field a to p
    Branch 0002_add_b
      + Add field b to p
  
  Created new merge migration <实验目录>
  0003_merge_0002_add_a_0002_add_b.py 的内容:
    # Generated by Django 6.1.1 on 2026-09-30 12:30
    from django.db import migrations
    class Migration(migrations.Migration):
        dependencies = [
            ('lab', '0002_add_a'),
            ('lab', '0002_add_b'),
        ]
        operations = [
        ]
  migrate → ['Applying lab.0002_add_b... OK', 'Applying lab.0002_add_a... OK', 'Applying lab.0003_merge_0002_add_a_0002_add_b... OK']

合并迁移只是一个把 dependencies 指向两个叶子的节点,operations 默认为空。如果两个分支的操作会互相影响(比如改同一个字段),要手工在合并迁移里补操作。

合并之后仍然可能出错

实测 · 本机执行输出
  [SQLite] 合并后 migrate: 没有报错;执行了 3 个迁移 | lab_p 的列: [('id', 'INTEGER'), ('name', 'varchar(20)'), ('x', 'INTEGER')]
  [PostgreSQL] 合并后 migrate: 报错:django.db.utils.ProgrammingError: column "x" of relation "lab_p" already exists | lab_p 的列: id:bigint, name:character varying, x:text

Django 不分析两个分支的操作是否兼容。而且不同数据库的表现不同:SQLite 通过重建表悄悄把问题掩盖了,PostgreSQL 则报错——在 SQLite 上测试通过的迁移不代表在生产数据库上也行。

分步演示:迁移冲突与合并

迁移冲突与合并
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / Python 3.14.7 / Django 6.1.1(默认用 SQLite,其它数据库会在文中注明),用 django.test.Client 或真实的本机服务器进程实测;计时用 time.perf_counter,数字每次运行会有小幅抖动。SQLite 与 PostgreSQL 16.15(本机临时实例,端口 9433)
    • 没有验证:三个及以上分支的合并、合并迁移里手工补操作、多个 app 之间的依赖冲突、run_before 的交互、在版本控制里预防冲突的流程建议
    京ICP备2026067502号-1京公网安备11010502063487号