确保您的迁移是线性的。
项目描述
确保您的迁移历史是线性的。
有关背景信息,请参阅入门博客文章。
通过我的书籍更聪明、更快速地工作,该书Boost Your Django DX涵盖了django-linear-migrations和其他许多工具,以提高您的开发体验。
需求
支持Python 3.8至3.12。
支持Django 3.2至5.1。
安装
首先, 使用pip安装
python -m pip install django-linear-migrations
其次, 将应用程序添加到您的INSTALLED_APPS设置
INSTALLED_APPS = [
...,
"django_linear_migrations",
...,
]
应用程序依赖于重写内置的makemigrations命令。 如果您的项目有一个自定义 makemigrations 命令, 确保包含您的自定义命令的应用程序位于django_linear_migrations之上,并且您的命令是其Command类的子类
# myapp/management/commands/makemigrations.py
from django_linear_migrations.management.commands.makemigrations import (
Command as BaseCommand,
)
class Command(BaseCommand):
...
第三, 检查第一方应用程序的自动检测。运行此命令
python manage.py create_max_migration_files --dry-run
此命令用于创建 max_migration.txt 文件(稍后将详细介绍)- 在干运行模式下,它会列出会创建此类文件的 app。它试图自动检测哪些 app 是第一方 app,即属于您的项目。自动检测检查 app 代码的路径,以查看它是否在虚拟环境中,但此检测有时可能会失败,例如在通过 -e 安装的可编辑包中。如果您看到列出的任何不属于您项目的 app,请定义 FIRST_PARTY_APPS 设置中第一方 app 标签的列表,并将其组合到 INSTALLED_APPS
FIRST_PARTY_APPS = []
INSTALLED_APPS = FIRST_PARTY_APPS + ["django_linear_migrations", ...]
(注意:Django 推荐您在项目中始终首先列出第一方 app,以便它们可以覆盖第三方和 contrib app 中的内容。)
第四,通过重新运行不带干运行标志的命令来为您的第一方 app 创建 max_migration.txt 文件。
python manage.py create_max_migration_files
将来,当您向项目添加新 app 时,您需要创建其 max_migration.txt 文件。根据需要将新 app 添加到 INSTALLED_APPS 或 FIRST_PARTY_APPS,然后通过指定其标签重新运行创建新 app 的创建命令。
python manage.py create_max_migration_files my_new_app
用法
django-linear-migrations 帮助您处理 Django 项目,在这些项目中,可能同时进行多个添加迁移的分支。它强制您的 app 具有线性迁移历史,避免合并迁移及其可能导致的由迁移运行顺序不同而产生的问题。它通过使 makemigrations 记录每个 app 的 max_migration.txt 文件中的最新迁移名称来实现。在并行开发迁移的情况下,这些文件将在您的源代码控制工具(Git、Mercurial 等)中引起合并冲突。对于 app 的第一个合并迁移将阻止第二个合并,而不解决冲突。包含的 rebase_migration 命令可以帮助自动解决此类冲突。
系统检查
django-linear-migrations 随附一些系统检查,以验证您的 max_migration.txt 文件是否同步。这些包括
dlm.E001: <app_label> 的 max_migration.txt 文件不存在。
dlm.E002: <app_label> 的 max_migration.txt 包含多行。
dlm.E003: <app_label> 的 max_migration.txt 指向不存在的迁移 ‘<bad_migration_name>’。
dlm.E004: <app_label> 的 max_migration.txt 包含 ‘<max_migration_name>’,但最新迁移是 ‘<real_max_migration_name>’。
dlm.E005: 检测到冲突迁移;迁移图中存在多个叶子节点: <conflicting_migrations>
create_max_migration_files 命令
python manage.py create_max_migration_files [app_label [app_label ...]]
此管理命令为所有第一方 app 或指定的标签创建 max_migration.txt 文件。它在 django-linear-migrations 的初始安装中使用,也用于重新创建。
通过传递 --dry-run 标志,仅列出将要创建的 max_migration.txt 文件。
通过传递 --recreate 标志重新创建已存在的文件。这在修改迁移后使用合并或手动修改后可能很有用。
rebase_migration 命令
此管理命令可以帮助您解决迁移冲突。在 Git 中的冲突 "rebase" 操作之后,使用 app 的名称运行它以自动解决迁移冲突
$ python manage.py rebase_migration <app_label>
命令使用 max_migration.txt 文件中的冲突信息来确定要重新合并的迁移。它自动检测 Git 合并或重新合并操作是否正在进行,如果找不到 Git 仓库则假定重新合并。然后
重命名迁移
将其修改为依赖于您主分支的新迁移
更新 max_migration.txt。
如果已安装 Black,则命令将使用它格式化更新的迁移文件,就像 Django 内置的迁移命令(从版本 4.1+)一样。下面有一些示例和注意事项。
请注意,重新合并迁移可能并不总是 正确 的做法。如果您的主分支和功能分支上的迁移都影响了相同的模型,将迁移重新合并到末尾可能没有意义。然而,这种并行更改通常会导致模型文件或其他源代码部分发生冲突。
工作示例
假设您在一个名为 titles 的功能分支上处理项目中的 books 应用程序,并创建了一个名为 0002_longer_titles 的迁移。同时,您的 main 分支已经合并了一个包含不同 2 号迁移的提交,该迁移名为 0002_author_nicknames。多亏了 django-linear-migrations,max_migration.txt 文件将显示为功能分支和主分支之间的冲突。
通过切换到功能分支 titles 并迁移到最后一个公共迁移来撤销您的本地数据库中的新迁移,以此开始修复。这是必要的,因为重新合并后它将被重命名并被视为未应用。
$ git switch titles
$ python manage.py migrate books 0001
然后,获取最新代码
$ git switch main
$ git pull
...
接下来,将 titles 分支基于最新代码进行重新合并。在此过程中,Git 将检测到 max_migration.txt 上的冲突。
$ git switch titles
$ git rebase main
Auto-merging books/models.py
CONFLICT (content): Merge conflict in books/migrations/max_migration.txt
error: could not apply 123456789... Increase Book title length
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 123456789... Increase Book title length
此时,books 应用程序的 max_migration.txt 内容可能看起来像这样
$ cat books/migrations/max_migration.txt
<<<<<<< HEAD
0002_author_nicknames
=======
0002_longer_titles
>>>>>>> 123456789 (Increase Book title length)
此时,使用 rebase_migration 自动修复 books 迁移历史记录
$ python manage.py rebase_migration books
Renamed 0002_longer_titles.py to 0003_longer_titles.py, updated its dependencies, and updated max_migration.txt.
这将在迁移历史记录的末尾放置冲突迁移。它将适当地重命名文件,修改其 dependencies = [...] 声明,并适当地更新 max_migration.txt 中命名的迁移。
之后,您应该可以继续重新合并
$ git add books/migrations
$ git rebase --continue
然后迁移本地数据库,以便您继续开发
$ python manage.py migrate books
Operations to perform:
Target specific migration: 0003_longer_titles, from books
Running migrations:
Applying books.0002_author_nicknames... OK
Applying books.0003_longer_titles... OK
代码格式化
rebase_migration 不能保证其编辑与您的代码风格一致。如果您使用像 Black 这样的格式化程序,您会在应用 rebase_migration 后运行它。
如果您使用 pre-commit,请注意,Git 在重新合并提交期间不会调用钩子。您可以通过 pre-commit run 在更改的文件上手动运行它。
包含多个提交的分支
想象一下与上面相同的示例,但您的功能分支有几个提交正在编辑迁移。这次,在将您的功能分支重新合并到最新的 main 分支之前,将功能分支上的提交压缩在一起。这样,rebase_migration 就可以在冲突发生时编辑迁移文件。
您可以使用以下命令进行此操作
$ git rebase -i --keep-base main
这将打开 Git 的 交互式模式 文件。编辑此文件,使每个第一个提交之后的提交都被压缩,方法是每行以“s”开头。然后关闭文件,重新合并将执行。
在此操作之后,您可以像前面的示例一样将分支重新合并到最新的 main 分支。
包含多个迁移的分支
rebase_migration 目前不支持将多个迁移(在同一应用程序中)进行变基。这是一个开放的功能请求,但不是优先事项,因为通常一次限制一个迁移的更改是一个好主意。在变基之前,请考虑将迁移合并为一个。
灵感
我在多个地方看到过类似于 django-linear-migrations 实现的技术,这成为了整合这个包的灵感。我的前客户 Pollen 和当前客户 ev.energy 都有实现。这篇文章 Doordash 博客文章 介绍了一个类似的系统,该系统使用单个文件来跟踪最新迁移。还有一个名为 django-migrations-git-conflicts 的包,其工作方式相当类似。
项目详情
下载文件
下载您平台的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。
源分布
构建分布
django_linear_migrations-2.13.0.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 91b5f29c7ba0c56131b5d789c71f5472431569e2f7a5990dec5f939e41b5300f |
|
MD5 | 5d01bb5b9bf6384047193ba55a59424c |
|
BLAKE2b-256 | 06d00a4166bbeb120a33401de973062ae1acd57551b7fb699e2bb1f4418cd31b |
django_linear_migrations-2.13.0-py3-none-any.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 4e26c5b123001371461a0b71b6df56e36e52909afe0538bbceb438f9e33c90fb |
|
MD5 | aaf4a7ddb3ce1dc8cb53b1ed55b8189e |
|
BLAKE2b-256 | 6c75dff691682e50b1bbd19521eb0ab2ff499a2fc3efca9f7006919ee75c6331 |