如何将数据库置于git(版本控制)下?

我正在做一个web应用程序,我需要为一些主要的更改做一个分支,事情是,这些更改需要更改数据库模式,所以我想把整个数据库放在git下。

我怎么做呢?是否有一个特定的文件夹,我可以保存在git存储库下?我怎么知道是哪个?我如何确定我放入了正确的文件夹?

我需要确定,因为这些更改是不向后兼容的;我可不能搞砸。

在我的例子中,数据库是PostgreSQL

编辑:

有人建议进行备份并将备份文件置于版本控制之下,而不是将数据库置于版本控制之下。说实话,我觉得这真的很难接受。

肯定有更好的办法。

更新:

好吧,没有更好的方法了,但我还是不太相信,所以我要稍微改变一下问题:

我想将整个数据库置于版本控制之下,我可以使用什么数据库引擎来将实际数据库置于版本控制之下,而不是转储?

sqlite是git友好的吗?

因为这只是开发环境,所以我可以选择任何我想要的数据库。

Edit2:

我真正想要的不是跟踪我的开发历史,而是能够从我的“新的根本性变化”分支切换到“当前稳定的分支”,并且能够修复一些错误/问题,等等,与当前稳定的分支。这样,当我切换分支时,数据库就会自动地与我当前所在的分支兼容。 我不太关心实际数据。

168717 次浏览

采用一个数据库转储,并对其进行版本控制。这样它就是一个平面文本文件。

我个人建议同时保留一个数据转储和一个模式转储。通过使用diff,可以相当容易地看到从一个修订到另一个修订的模式中发生了哪些变化。

如果您正在进行大的更改,那么您应该有一个用于进行新模式更改的辅助数据库,而不会触及旧数据库,因为正如您所说的,您正在进行一个分支。

没有原子性就无法做到这一点,如果不使用pg_dump或快照文件系统,就无法获得原子性。

我的postgres实例在zfs上,我偶尔会对它进行快照。它几乎是即时和一致的。

我认为X-Istence在正确的轨道上,但你可以对这一策略进行更多的改进。首先,使用:

$pg_dump --schema ...

转储表、序列等,并将此文件置于版本控制之下。您将使用它来分离分支之间的兼容性更改。

接下来,为一组包含配置要求的表执行数据转储,以供应用程序操作(可能应该跳过用户数据等),如表单默认值和其他数据,非用户可修改的数据。你可以有选择地使用:

$pg_dump --table=.. <or> --exclude-table=..

这是一个好主意,因为当数据库达到100Mb以上时,在进行完整的数据转储时,回购会变得非常笨拙。更好的办法是备份你测试应用所需的最小数据集。如果你的默认数据非常大,这仍然可能导致问题。

如果您确实需要在回购中放置完全备份,请考虑在源代码树之外的分支中进行备份。不过,一个引用了匹配的svn rev的外部备份系统可能是最好的。

另外,我建议在修改时使用文本格式转储而不是二进制格式转储(至少对于模式而言),因为这些格式转储更容易区分。

最后,看看Postgres备份文档(如果你还没有的话)。你评论备份“数据库”而不是转储的方式让我怀疑你是否在考虑基于文件系统的备份(注意事项请参阅23.2节)。

我开始想一个非常简单的解决方案,不知道为什么我以前没有想到!!

  • 复制数据库(包括模式和数据)。
  • 在new-major-changes的分支中,只需更改项目配置以使用新的重复数据库。

这样我就可以切换分支,而不用担心数据库模式更改。

编辑:

重复,我的意思是创建另一个具有不同名称的数据库(如my_db_2);不是去倾倒之类的东西。

使用像LiquiBase这样的东西可以让你保持对Liquibase文件的修订控制。您可以仅为生产标记更改,并让lb为生产或开发(或任何您想要的方案)使您的DB保持最新。

这个问题基本上已经回答了,但我想用一个小建议来补充X-Istence和Dana the Sane的回答。

如果你需要某种粒度的修订控制,比如每天,你可以用rdiff-backup这样的工具来耦合表和模式的文本转储,它可以进行增量备份。这样做的好处是,不存储每日备份的快照,而只存储与前一天的差异。

这样你就有了修订控制的优势,也不会浪费太多的空间。

在任何情况下,直接在频繁更改的大平面文件上使用git都不是一个好的解决方案。如果数据库变得太大,git在管理文件时会出现一些问题。

使用像iBatis Migrations (手册简短的教程视频)这样的工具,它允许你在项目的整个生命周期中对数据库进行版本控制,而不是数据库本身。

这允许您有选择地将单个更改应用到不同的环境中,记录哪些更改在哪些环境中,创建脚本以应用从a到N的更改、回滚更改等等。

有一个伟大的项目叫做“教义下的移民”,就是为了这个目的而建立的。

它仍然处于alpha状态,是为php构建的。

http://docs.doctrine-project.org/projects/doctrine-migrations/en/latest/index.html

实际上,你想要的可能是类似的东西,它在数据库中存储数据库的版本。检查这个演讲

这个项目显然没有任何进展,所以它可能不会马上帮到你,但这是一个有趣的概念。我担心正确地做到这一点会非常困难,因为即使是版本1也必须获得所有的细节,以便让人们信任他们的工作。

我想把整个数据库置于版本控制之下 我可以使用数据库引擎,这样我就可以把实际的数据库 版本控制而不是它的转储?< / p >

这与数据库引擎无关。在Microsoft SQL Server上有很多版本控制程序。我不认为git可以解决这个问题,你必须使用pgsql特定的模式版本控制系统。我不知道这样的事情是否存在……

以下是我在项目中尝试做的事情:

  • 分离数据、模式和默认数据。

数据库配置存储在不受版本控制的配置文件中(.gitignore)

数据库默认值(用于设置新项目)是一个受版本控制的简单SQL文件。

对于数据库模式,在版本控制下创建数据库模式转储。

最常见的方法是使用包含SQL语句的更新脚本(ALTER Table..或更新)。你还需要在你的数据库中有一个地方来保存你的模式的当前版本)

看看其他大型开源数据库项目(piwik,或者你最喜欢的cms系统),它们都使用updatescripts (1.sql,2.sql,3.sh,4.php.5.sql)

但这是一项非常耗时的工作,您必须创建并测试更新脚本,还需要运行一个通用的更新脚本来比较版本并运行所有必要的更新脚本。

所以理论上(这就是我正在寻找的)你可以 在每次更改后转储数据库模式(手动,conjob, git钩子(可能在提交之前)) (并且只在一些非常特殊的情况下创建更新脚本)

之后,在您的普通updatescript中(对于特殊情况,运行正常的updatescript),然后比较模式(转储和当前数据库),然后自动生成必要的ALTER语句。已经有一些工具可以做到这一点,但还没有找到一个好的工具。

我推荐neXtep(链接被删除-域名被nsfw网站接管)来控制数据库的版本,它有一组很好的文档和论坛,解释了如何安装和遇到的错误。我已经对postgreSQL 9.1和9.3进行了测试,我能够让它在9.1中工作,但在9.3中似乎无法工作。

我在我的个人项目中做的是,我把我的整个数据库存储到dropbox,然后点MAMP, WAMP工作流,从那里使用它。这样,数据库总是最新的,无论我需要做一些开发。但这只是针对开发!现场是使用自己的服务器,当然!:)

在git版本控制下存储数据库的每一层都在变化就像每次提交时推送你的整个数据库,每次pull时推送你的恢复整个数据库。 如果你的数据库很容易发生重大变化,而且你不能失去它们,你可以只更新你的pre_commitpost_merge钩子。 我对我的一个项目做了同样的事情,你可以找到方向在这里.

看一下RedGate SQL源代码控制。

http://www.red-gate.com/products/sql-development/sql-source-control/

这个工具是一个SQL Server Management Studio管理单元,它允许你用Git把你的数据库放在源代码控制下。

每个用户495美元的价格有点贵,但有28天的免费试用。

< p >注意 我和RedGate没有任何关系。

我遇到过这个问题,因为我有一个类似的问题,其中一些近似于基于DB的目录结构,存储“文件”,我需要git来管理它。它是分布式的,在云上使用复制,因此它的接入点将通过MySQL。

上述答案的要点,似乎类似地提出了一个问题的替代解决方案,使用Git来管理数据库中的一些东西,这有点错过了重点,所以我将尝试回答这个问题。

Git是一个系统,它在本质上存储了一个增量(差异)数据库,可以对其进行重新组装,以重现上下文。git的正常使用假设上下文是一个文件系统,而那些增量是该文件系统中的diff,但实际上所有git都是一个增量的分层数据库(分层,因为在大多数情况下,每个增量都是一个至少有一个父级的提交,以树状排列)。

理论上,只要你能生成一个增量,git就可以存储它。问题是git通常期望它生成delta的上下文是一个文件系统,类似地,当您签出git层次结构中的一个点时,它期望生成一个文件系统。

如果您想在数据库中管理变更,您有两个离散的问题,我将分别处理它们(如果我是您的话)。第一个是模式,第二个是数据(尽管在你的问题中,你说数据不是你关心的东西)。我过去遇到的一个问题是Dev和Prod数据库,其中Dev可以对模式进行增量更改,而这些更改必须在CVS中进行记录,并传播到活动中,同时还要对几个“静态”表中的一个进行添加。我们通过第三个数据库Cruise来做到这一点,它只包含静态数据。在任何时候,都可以比较来自Dev和Cruise的模式,我们有一个脚本来获取这两个文件的差异,并生成一个包含ALTER语句的SQL文件,然后应用它。类似地,任何新数据都可以提炼为包含INSERT命令的SQL文件。只要只添加字段和表,而不删除字段和表,该流程就可以自动生成SQL语句来应用增量。

git生成增量的机制是diff,它将一个或多个增量与一个文件结合的机制是merge。如果你能想出一个方法来从不同的上下文中进行区分和合并,git应该可以工作,但正如前面讨论的,你可能更喜欢一个工具来为你做这件事。我对解决这个问题的第一个想法是这个https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration#External-Merge-and-Diff-Tools,它详细说明了如何替换git的内部差异和合并工具。当我提出更好的解决方案时,我会更新这个答案,但在我的情况下,我希望只需要管理数据更改,因为基于DB的文件存储可能会更改,所以我的解决方案可能不是您所需要的。

我就是这么做的:

因为你可以自由选择DB类型,使用一个基于文件的DB,如火鸟。

创建一个模板DB,它具有适合您实际分支的模式,并将其存储在存储库中。

当以编程方式执行应用程序时,创建模板DB的副本,将其存储在其他地方并使用该副本。

通过这种方式,您可以在没有数据的情况下将DB模式置于版本控制之下。如果你改变模式,你只需要改变模板DB

我们曾经在一个标准的LAMP配置上运行一个社交网站。我们有一个活动服务器、测试服务器和开发服务器,以及本地开发人员机器。所有这些都使用GIT进行管理。

在每台机器上,我们都有PHP文件,还有MySQL服务,以及一个用户可以上传的包含图像的文件夹。Live服务器增长到有大约10万(!)个循环用户,转储大约是2GB(!),图像文件夹大约是50GB(!)。当我离开的时候,我们的服务器已经达到了CPU、Ram的极限,最重要的是,同时的网络连接限制(我们甚至编译了自己版本的网卡驱动程序来最大限度地使用服务器的lol)。我们不能(你也不应该在你的网站上假设)在GIT中放入2GB的数据和50GB的图像。

为了在GIT下轻松地管理所有这些内容,我们将忽略二进制文件夹(包含图像的文件夹),将这些文件夹路径插入到.gitignore中。在Apache documentroot路径之外还有一个名为SQL的文件夹。在这个SQL文件夹中,我们将以增量编号(001.florianm)放入来自开发人员的SQL文件。001. sql,约翰。sql, 002. florianm。sql等等)。这些SQL文件也由GIT管理。第一个sql文件确实包含大量的DB模式。我们不会在GIT中添加用户数据(例如用户表或评论表的记录),但是像配置或拓扑或其他特定于站点的数据,在sql文件中维护(因此由GIT维护)。关于SQL模式和数据,GIT主要是由开发人员(他们最了解代码)来决定哪些不需要维护。

当它发布时,管理员登录到开发服务器,将活动分支与开发机器上的所有开发人员和所需分支合并为更新分支,并将其推到测试服务器。在测试服务器上,他检查Live服务器的更新过程是否仍然有效,并快速连续地将Apache中的所有流量指向一个占位符站点,创建一个DB转储,将工作目录从' Live '指向'update',将所有新的sql文件执行到mysql中,并将流量重新指向正确的站点。当所有涉众在审查测试服务器后达成一致时,管理员从测试服务器到活动服务器做了同样的事情。然后,他将生产服务器上的活动分支合并到所有服务器上的主分支,并重新基于所有活动分支。开发人员自己负责重新建立他们的分支,但他们通常知道自己在做什么。

如果测试服务器上有问题,例如。合并有太多冲突,然后代码被恢复(将工作分支指向'live'), SQL文件永远不会执行。在执行sql文件时,这被认为是一个不可逆的操作。如果SQL文件不能正常工作,则使用Dump恢复DB(开发人员被告知,因为提供了测试不佳的SQL文件)。

今天,我们同时维护一个sql-up和sql-down文件夹,它们具有相同的文件名,开发人员必须测试这两个正在升级的sql文件是否可以同样降级。这最终可以用bash脚本来执行,但是如果有人一直监视升级过程,这是个好主意。

虽然不是很好,但还是可以控制的。希望这能让你深入了解一个真实的、实用的、相对高可用性的站点。也许它有点过时,但仍然被遵循。

我已经发布了一个sqlite工具,它可以满足您的要求。它使用一个自定义的差异驱动程序,利用sqlite项目工具'sqldiff', uuid作为主键,并去掉sqlite rowid。它仍然处于alpha阶段,所以反馈是非常感谢的。

Postgres和mysql比较棘手,因为二进制数据保存在多个文件中,即使您能够对其进行快照,也可能无效。

https://github.com/cannadayr/git-sqlite

我想做一些类似的事情,将我的数据库更改添加到我的版本控制系统。

我将遵循Vladimir Khorikov在这篇文章中的想法“数据库版本控制最佳实践”。总之,我将

  • 在源代码控制系统中存储它的模式和引用数据。
  • 对于每一个修改,我们将创建一个单独的SQL脚本

万一有用的话!

  • Irmin(分支+时间旅行)
  • Flur.ee(不可变+时间旅行+图形查询)
  • XTDB(以前称为“CruxDB”)(时间旅行+查询)
  • TerminusDB(不可变+分支+时间旅行+图表查询!)
  • DoltDB(分支+时间旅行+ SQL查询)
  • 可自乘的(分支+远程状态验证)
  • EdgeDB(没有实时时间旅行,但是在模式更改后由编译器派生的迁移)
  • Migra(用于Postgres模式/数据。自动生成迁移脚本,自动同步数据库状态)
  • ImmuDB(不可变+时间旅行)

2019年8月26日更新:

Netlify CMS是用GitHub做的,一个示例实现可以在这里找到关于他们如何实现netlify-cms-backend-github的所有信息

我说不要。数据在任何时候都可能改变。相反,你应该只在你的代码、模式和表定义(create databasecreate table语句)和单元测试的示例数据中提交数据模型。这就是Laravel的工作方式,提交数据库迁移和种子。

使用版本控制的数据库,现在有几个这样的数据库。

https://www.dolthub.com/blog/2021-09-17-database-version-control/

这些产品没有在其他类型的数据库上应用版本控制——它们是自己的数据库引擎,支持版本控制操作。因此,您需要迁移到它们,或者在它们的基础上开始构建。

我编写了其中一个,DoltDB,它结合了MySQL和Git的接口。看看这里:

https://github.com/dolthub/dolt