繁体   English   中英

如何将数据库放在 git 下(版本控制)?

[英]How can I put a database under git (version control)?

我正在做一个 web 应用程序,我需要为一些重大更改创建一个分支,问题是,这些更改需要更改数据库架构,所以我想将整个数据库也放在 git 下。

我怎么做? 有没有我可以保存在 git 存储库下的特定文件夹? 我怎么知道是哪一个? 我怎样才能确定我放的是正确的文件夹?

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

我的数据库是 PostgreSQL

编辑:

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

一定有更好的方法。

更新:

好的,所以没有更好的方法,但我仍然不太相信,所以我会稍微改变一下问题:

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

sqlite 对 git 友好吗?

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

编辑2:

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

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

我个人建议您同时保留数据转储和模式转储。 通过这种方式,使用 diff 可以很容易地查看从修订版到修订版的架构中发生了什么变化。

如果您要进行重大更改,则应该有一个辅助数据库,您可以对其进行新架构更改,而不是触及旧数据库,因为正如您所说,您正在创建一个分支。

查阅Refactoring Databases( http://databaserefactoring.com/ ),了解一堆很好的技巧来保持数据库与代码更改的同时进行。

可以说您在问错误的问题。 而不是将数据库放入git,您应该将更改分解为可验证的小步骤,以便您可以轻松迁移/回滚架构更改。

如果您希望具有完全的可恢复性,则应考虑归档postgres WAL日志,并使用PITR(时间点恢复)将事务回放/转发到特定的已知良好状态。

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

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

这样我就可以切换分支而不必担心数据库架构的变化。

编辑:

重复,我的意思是创建另一个具有不同名称的数据库(如my_db_2 ); 不做转储或类似的事情。

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

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

上述答案的要点似乎同样为所提出的问题提出了一种替代解决方案,这种解决方案忽略了使用 Git 管理数据库中的某些内容的要点,因此我将尝试回答该问题。

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

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

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

git 生成 deltas 的机制是diff ,它将 1 个或多个 deltas 与文件组合的机制称为merge 如果您能想出一种从不同上下文进行差异和合并的方法,git 应该可以工作,但正如已经讨论过的,您可能更喜欢为您执行此操作的工具。 我解决这个问题的第一个想法是https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration#External-Merge-and-Diff-Tools ,它详细介绍了如何替换 git 的内部差异和合并工具。 我会更新这个答案,因为我想出了一个更好的解决方案,但在我的情况下,我希望只需要管理数据更改,就基于数据库的文件存储可能会更改而言,所以我的解决方案可能不是您所需要的。

有一个伟大的项目,叫做 Doctrine 下的迁移,就是为此目的而构建的。

它仍处于 alpha 状态并为 php 构建。

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

  • Irmin (分支+时间旅行)
  • Flur.ee (不可变+时间旅行)
  • Crux DB (时间旅行)
  • TerminusDB(分支+时间旅行)
  • DoltDB (分支+时间旅行)

一段时间以来,我一直在为 Postgres(或一般的 SQL 数据库)寻找相同的功能,但我发现没有足够合适(简单且直观)的工具。 这可能是由于数据存储方式的二进制性质。 Klonio听起来很理想,但看起来已经死了。 Noms DB看起来很有趣(而且还活着)。 另请查看Irmin (基于 OCaml 的 Git 属性)。

尽管这并不能回答问题,因为它可以与 Postgres 一起使用,但请查看Flur.ee数据库。 它具有“时间旅行”功能,允许您从任意时间点查询数据。 我猜它应该能够使用“分支”模型。

该数据库最近正在为区块链目的而开发。 由于区块链的性质,数据需要以增量方式记录,这正是 git 的工作原理。 他们的目标是在 2019 年第二季度发布开源版本

因为每个 Fluree 数据库都是一个区块链,所以它存储了每笔交易的完整历史记录。 这是区块链如何确保信息不可变和安全的一部分

更新:还可以查看Crux 数据库,它可以查询插入的时间维度,您可以将其视为“版本”。 Crux 似乎是备受好评的 Datomic 的开源实现。 但是,它不支持 Dolt 和 Git 那样的分支。

Crux 是一个双时态数据库,用于存储交易时间和有效时间历史。 虽然 [uni]temporal 数据库支持“时间旅行”查询从数据库创建到当前状态的数据库状态的事务序列,但 Crux 还提供对离散有效时间轴的“时间旅行”查询,而无需不必要的设计复杂性或性能影响。 这意味着 Crux 用户可以用过去和未来的信息填充数据库,而不管信息到达的顺序,并对过去的记录进行更正以构建给定域的不断改进的时间模型。

更新 II查看 Terminus DB:“TerminusDB 的文档 - 一个存储像 git 这样的数据的开源图形数据库”。 它支持 Dolt 和 Git 等分支,但看起来还不是很成熟。

更新 III NomsDB 被分叉,现在在 DoltDB 中使用: https : //github.com/dolthub/dolt

面临类似的需求,这是我对数据库版本控制系统的研究:

  1. Sqitch-基于Perl的开源; 适用于所有主要数据库,包括PostgreSQL https://github.com/sqitchers/sqitch
  2. Mahout-仅适用于PostgreSQL; 开源数据库架构版本控制。 https://github.com/cbbrowne/mahout
  3. Liquibase-另一个开源数据库版本控制软件。 免费版本的Datical。 http://www.liquibase.org/index.html
  4. Datical - Liquibase的商业版本- https://www.datical.com/
  5. BoxFuse的Flyway-商业广告。 https://flywaydb.org/
  6. 另一个开源项目https://gitlab.com/depesz/Versioning作者在此处提供了指南: https//www.depesz.com/2010/08/22/versioning/
  7. 红门变更自动化-仅适用于SQL Server。 https://www.red-gate.com/products/sql-development/sql-change-automation/

看看 RedGate SQL 源代码控制。

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

此工具是一个 SQL Server Management Studio 管理单元,它允许您使用 Git 将数据库置于源代码控制之下。

每位用户 495 美元有点贵,但有 28 天的免费试用期。

注意我与 RedGate 没有任何关联。

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

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

  • 将其架构和参考数据存储在源控制系统中。
  • 对于每次修改,我们将创建一个单独的 SQL 脚本,其中包含更改

万一有帮助!

我已经发布了一个 SQLite 工具,可以满足您的要求。 它使用自定义 diff 驱动程序,利用 sqlite 项目工具 'sqldiff',UUID 作为主键,并且不使用 sqlite rowid。 它仍处于 alpha 阶段,因此非常感谢您的反馈。

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

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

从本质上讲,您想要的可能类似于Post Facto ,它将数据库的版本存储在数据库中。 检查此演示文稿

这个项目显然从来没有真正去任何地方,所以它可能不会立即帮助你,但它是一个有趣的概念。 我担心正确地执行此操作会非常困难,因为即使是第 1 版也必须正确处理所有细节才能让人们信任他们的工作。

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

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

我会推荐 neXtep(链接已删除 - 域被 NSFW 网站接管)用于版本控制数据库它有一套很好的文档和论坛,解释了如何安装和遇到的错误。 我已经针对 postgreSQL 9.1 和 9.3 对其进行了测试,我能够让它在 9.1 上工作,但对于 9.3 似乎不起作用。

我在我的个人项目中所做的是,将我的整个数据库存储到 Dropbox,然后指向 MAMP、WAMP 工作流程以从那里直接使用它。 但这仅适用于开发人员! 实时站点正在使用自己的服务器! :)

在 git 版本控制下存储每个级别的数据库更改就像在每次提交时推送整个数据库,并在每次拉取时恢复整个数据库。 如果您的数据库很容易发生重大更改,并且您无法承受丢失它们,那么您只需更新pre_commitpost_merge挂钩即可。 我对我的一个项目做了同样的事情,你可以在这里找到方向。

这个问题几乎得到了回答,但我想用一个小建议来补充 X-Istence 和 Dana the Sane 的回答。

如果您需要某种程度的修订控制,例如每天,您可以将表和模式的文本转储与诸如rdiff-backup 之类的工具进行增量备份。 优点是无需存储每日备份的快照,只需存储与前一天的差异即可。

有了这个,您既拥有版本控制的优势,又不会浪费太多空间。

在任何情况下,直接在经常更改的大型平面文件上使用 git 都不是一个好的解决方案。 如果您的数据库变得太大,git 将开始在管理文件时遇到一些问题。

我就是这样做的:

由于您可以自由选择 DB 类型,因此请使用基于文件的 DB,例如 firebird。

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

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

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

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

在每台机器上,我们都有 PHP 文件,还有 MySQL 服务,以及一个包含用户上传图像的文件夹。 Live 服务器增长到有大约 100K (!) 的经常用户,转储大约是 2GB (!),Image 文件夹大约有 50GB (!)。 到我离开时,我们的服务器已达到其 CPU、Ram 和最重要的并发网络连接限制的限制(我们甚至编译了我们自己的网卡驱动程序版本以最大化服务器 'lol')。 我们不能(也不应该假设您的网站)在 GIT 中放入 2GB 的数据和 50GB 的图像。

为了在 GIT 下轻松管理所有这些,我们将通过将这些文件夹路径插入 .gitignore 来忽略二进制文件夹(包含图像的文件夹)。 我们在 Apache 文档根路径之外还有一个名为 SQL 的文件夹。 在那个 SQL 文件夹中,我们会将来自开发人员的 SQL 文件按递增编号方式放置(001.florianm.sql、001.johns.sql、002.florianm.sql 等)。 这些 SQL 文件也由 GIT 管理。 第一个 sql 文件确实会包含大量的 DB 模式。 我们不会在 GIT 中添加用户数据(例如,用户表或评论表的记录),但是配置或拓扑或其他站点特定数据等数据是在 sql 文件中维护的(因此由 GIT 维护)。 大多数情况下,开发人员(最了解代码的人)决定了 GIT 在 SQL 模式和数据方面维护什么和不维护什么。

当它发布时,管理员登录到开发服务器,将实时分支与所有开发人员和开发机器上需要的分支合并到更新分支,并将其推送到测试服务器。 在测试服务器上,他检查 Live 服务器的更新过程是否仍然有效,然后快速连续地将 Apache 中的所有流量指向一个占位符站点,创建一个数据库转储,将工作目录从“live”指向“update” ',将所有新的 sql 文件执行到 mysql 中,并将流量重新指向正确的站点。 当所有利益相关者在审查测试服务器后都同意时,管理员从测试服务器到实时服务器做了同样的事情。 之后,他将生产服务器上的 live 分支合并到所有服务器上的 master 分支,并对所有 live 分支重新定位。 开发人员负责自己重新设置他们的分支,但他们通常知道他们在做什么。

如果测试服务器上出现问题,例如。 合并有太多冲突,然后代码被还原(将工作分支指向“实时”)并且从未执行过 sql 文件。 在执行 sql 文件的那一刻,这在当时被认为是不可逆的操作。 如果 SQL 文件不能正常工作,则使用 Dump 恢复数据库(开发人员被告知,因为提供了未经测试的 SQL 文件)。

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

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

我说不要。 数据可以随时更改。 相反,您应该只在代码、架构和表定义( create databasecreate table语句)中提交数据模型以及单元测试的示例数据。 这有点像 Laravel 的做法,提交数据库迁移和种子。

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

$pg_dump --schema ... 

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

接下来,对包含应用程序运行所需配置(可能应该跳过用户数据等)的一组表执行数据转储,例如表单默认值和其他数据非用户可修改数据。 您可以使用以下方法有选择地执行此操作:

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

这是一个好主意,因为当您的数据库在执行完整数据转储时达到 100Mb+ 时,repo 会变得非常笨重。 一个更好的主意是备份测试应用程序所需的最少数据集。 但是,如果您的默认数据非常大,这仍然可能会导致问题。

如果您绝对需要在 repo 中放置完整备份,请考虑在源树之外的分支中执行此操作。 不过,参考匹配的 svn rev 的外部备份系统可能是最好的。

此外,我建议在二进制文件上使用文本格式转储用于修订目的(至少对于架构而言),因为它们更容易区分。 您始终可以在办理登机手续之前压缩这些文件以节省空间。

最后,如果您还没有,请查看postgres 备份文档 您评论备份“数据库”而不是转储的方式让我怀疑您是否正在考虑基于文件系统的备份(有关警告,请参阅第23.2节)。

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

  • 将数据和架构以及默认数据分开。

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

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

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

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

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

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

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

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

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

这允许您有选择地将单个更改应用于不同的环境,保留哪些更改在哪些环境中的更改日志,创建脚本以应用更改 A 到 N,回滚更改等。

2019 年 8 月 26 日更新:

Netlify CMS正在使用 GitHub 进行此操作,可以在此处找到示例实现,其中包含有关如何实现它的所有信息netlify-cms-backend-github

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

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

这些产品不在另一种类型的数据库之上应用版本控制——它们是它们自己的支持版本控制操作的数据库引擎。 因此,您首先需要迁移到它们或开始构建它们。

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

https://github.com/dolthub/dolt

我希望它更简单。 将模式作为文本文件签入是捕获数据库结构的良好开端。 但是,对于内容,我还没有找到比 CSV 文件更干净、更好的 git 方法。 每桌一张。 然后可以在多个分支上编辑数据库并非常好地合并。

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

这与数据库引擎无关。 Microsoft SQL Server 有很多版本控制程序。 我不认为这个问题可以用 git 解决,你必须使用 pgsql 特定的模式版本控制系统。 不知道有没有这种东西...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM