描述有点复杂,但我会尽我所能。基本上我们使用Git工作流程,这意味着我们有以下分支:
所以,这里真的很复杂。但是,由于我们的应用程序是针对MySQL数据库运行的Web应用程序,因此新功能通常需要更改数据库方案。为了自动执行此操作,我们使用dbdeploy,它允许我们在给定数字的情况下创建alter脚本。例如。 00001.sql,00002.sql等。在合并到集成分支时,dbdeploy将检查哪个更改脚本的编号高于该特定数据库上最新执行的脚本,并将执行这些脚本。
现在假设以下内容。 - 集成已将脚本更改为00200.sql。所有这些都在集成数据库上执行。 - 开发人员John有一个功能分支featureX,它是在集成仍然有00199.sql作为最高的alter脚本时创建的。
由于一些必需的数据库架构更改,John创建了00200.sql。
现在,在某些时候,John会将他的修改合并回集成分支。 John将发生合并冲突,并且会看到他的00200.sql已经存在于集成中。这意味着他需要打开冲突的文件,提取他的内容,将该文件重置回“我的”。 (整合中的原始状态)并将自己的内容放在新文件中。
现在,由于我们与十位开发人员合作,我们每天都会遇到这种情况。虽然我们确实理解了背后的原因,但它有时非常麻烦。 John重命名他的脚本,对集成执行合并提交,将更改推送到上游只是为了看到其他人已经创建了00201.sql,要求John再次进行处理。
当然必须有更多团队使用Git工作流并使用数据库更改管理工具来自动化数据库架构更改?
所以,简而言之,我的问题是:
任何其他提示都是最受欢迎的。
答案 0 :(得分:4)
Rails曾经这样做,完全解决了你描述的问题。他们改为以下方案:文件(rails称为迁移)标记为创建文件时的utc时间戳,例如
20140723069701_add_foo_to_bar
(名称的第二部分对订购没有贡献)。
Rails记录已运行的所有迁移的时间戳。当您要求它运行挂起的迁移时,它会选择其时间戳不在已运行的迁移列表中的所有迁移文件,并按数字顺序运行它们。
除非两个人在完全相同的时间点创建一个,否则您将不会再发生合并冲突。
文件仍按照您编写的顺序执行,但可能与其他人的工作交错。从理论上讲,您仍然可能遇到问题 - 例如,开发人员决定重命名我决定添加列的表。这比2个开发人员对数据库进行任何更改都要少得多,你甚至不会考虑模式更改,因为我只是编写了一个查询不再存在的表的代码 - 在某些时候,开发相关工作的开发人员会有互相交谈!
答案 1 :(得分:2)
一些建议:
1 - 看看Liquibase,每个版本都会获得一个引用需要发生的更改的文件,然后可以使用有意义的字符串而不是数字来命名更改文件。
2 - 拥有获取下一个可用号码的中心位置,然后人们使用最新号码。
我过去使用过Liquibase,非常成功,我们没有你描述的问题。
答案 2 :(得分:1)
作为Frederick Cheung suggested,使用时间戳而不是序列号。按日期戳顺序应用架构更改应该有效,因为架构更改只能依赖于先前日期的更改。
此外,在alter脚本的名称中包含开发人员的名称。这样可以100%防止合并冲突。
您的合并挂钩应该只查找新添加的alter脚本(存在于合并的分支中但不在上游分支中)并按时间戳的顺序执行它们。
答案 3 :(得分:0)
我过去曾使用两种不同的方法来解决您的问题。
第一种是使用可以处理架构更新的n ORM。
另一种方法是创建一个脚本,逐步构建数据库模式。这样,如果开发人员需要在表中添加一行,他应该在创建表后添加适当的sql语句。同样,如果他需要一个新表,他应该为此添加sql语句。然后合并成为确保事情按正确顺序发生的问题。这基本上是ORM中数据库更新过程的作用。这样的脚本需要非常防御性地编码,并且每个语句应检查其是否存在必要条件。
答案 4 :(得分:0)
对于dbvc commandline tool,我使用git log
来确定更新脚本的顺序。
git log -c --no-merges --pretty="format:" --name-status -p dev/db/updates/ | \
grep '^A' | awk '{print $2}' | tac
在这种情况下,提交顺序的方式将决定运行更新的顺序。这很可能是你想要的。
git merge b
,则将首先运行来自master的更新,而不是来自B。git rebase b
,则B中的更新将首先运行,而不是从主服务器运行。