如何处理来自不同Git功能分支的多个db alter脚本?

时间:2014-07-09 15:56:50

标签: database git dbdeploy

描述有点复杂,但我会尽我所能。基本上我们使用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工作流并使用数据库更改管理工具来自动化数据库架构更改?

所以,简而言之,我的问题是:

  • 如何在处理不同功能分支时自动执行数据库架构更改,这些功能分支在同一个数据库的不同实例上运行?
  • 如何一直防止合并冲突,同时仍然可以选择在执行的alter脚本中拥有固定的顺序?例如。 00199.sql必须在00200.sql之前执行,因为00200.sql可能取决于在00199.sql中完成的事情。

任何其他提示都是最受欢迎的。

5 个答案:

答案 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中的更新将首先运行,而不是从主服务器运行。