我正在做一个 web 应用程序,我需要为一些重大更改创建一个分支,问题是,这些更改需要更改数据库模式,所以我也想将整个数据库放在 git 下。
我怎么做?有没有可以保存在 git 存储库下的特定文件夹?我怎么知道是哪一个?我如何确定我放置了正确的文件夹?
我需要确定,因为这些更改不向后兼容;我不能搞砸了。
我的数据库是 PostgreSQL
编辑:
有人建议进行备份并将备份文件而不是数据库置于版本控制之下。老实说,我觉得这真的很难接受。
一定有更好的方法。
更新:
好的,所以没有更好的方法,但我仍然不太相信,所以我会稍微改变一下问题:
我想将整个数据库置于版本控制之下,我可以使用什么数据库引擎,以便将实际数据库置于版本控制之下而不是转储?
sqlite 对 git 友好吗?
由于这只是开发环境,我可以选择我想要的任何数据库。
编辑2:
我真正想要的不是跟踪我的开发历史,而是能够从我的“新的根本变化”分支切换到“当前稳定的分支”,并且能够修复一些错误/问题等,使用当前稳定的分支。这样当我切换分支时,数据库会自动神奇地与我当前所在的分支兼容。我不太关心实际数据。
进行数据库转储,然后进行版本控制。这样它是一个平面文本文件。
我个人建议您同时保留数据转储和模式转储。通过这种方式,使用 diff 可以很容易地查看架构中从修订到修订的变化。
如果您正在进行重大更改,您应该有一个辅助数据库,您可以对新架构进行更改,并且不要触及旧数据库,因为正如您所说的那样,您正在创建一个分支。
我开始想一个非常简单的解决方案,不知道为什么我以前没有想到它!
复制数据库(模式和数据)。
在 new-major-changes 的分支中,只需更改项目配置以使用新的重复数据库。
这样我就可以切换分支而不用担心数据库模式的变化。
编辑:
通过重复,我的意思是创建另一个具有不同名称的数据库(例如 my_db_2
);不做转储或类似的事情。
使用 LiquiBase 之类的内容可以让您保持对 Liquibase 文件的修订控制。您可以仅为生产标记更改,并让 lb 为生产或开发(或您想要的任何方案)保持您的数据库是最新的。
Irmin(分支+时间旅行)
Flur.ee(不可变+时间旅行+图查询)
Crux DB(时间旅行+查询)
TerminusDB(不可变+分支+时间旅行+图查询!)
DoltDB(分支+时间旅行+SQL查询)
Quadrable(分支+远程状态验证)
EdgeDB(不是实时旅行,而是由编译器在架构更改后派生的迁移)
Migra(Postgres 模式/数据的差异。自动生成迁移脚本,自动同步数据库状态)
ImmuDB(不可变+时间旅行)
我遇到了这个问题,因为我遇到了类似的问题,其中一些近似于基于数据库的目录结构,存储“文件”,我需要 git 来管理它。它使用复制在云中分布,因此它的访问点将通过 MySQL。
上述答案的要点似乎同样建议了一个替代解决方案来解决所提出的问题,这有点忽略了使用 Git 管理数据库中的某些内容,所以我将尝试回答这个问题。
Git 是一个系统,它本质上存储了一个增量(差异)数据库,可以重新组合以重现上下文。 git 的正常用法假定上下文是一个文件系统,并且这些增量是该文件系统中的差异,但实际上所有 git 都是增量的分层数据库(分层的,因为在大多数情况下,每个增量是一个至少 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 的内部差异和合并工具。我会更新这个答案,因为我想出了一个更好的问题解决方案,但在我的情况下,我希望只需要管理数据更改,到目前为止,基于数据库的文件存储可能会发生变化,所以我的解决方案可能不是您所需要的。
有一个名为 Migrations under Doctrine 的伟大项目就是为此目的而构建的。
它仍处于 alpha 状态并为 php 构建。
http://docs.doctrine-project.org/projects/doctrine-migrations/en/latest/index.html
看看 RedGate SQL 源代码控制。
http://www.red-gate.com/products/sql-development/sql-source-control/
此工具是一个 SQL Server Management Studio 管理单元,可让您使用 Git 将数据库置于源代码控制之下。
每位用户 495 美元有点贵,但有 28 天的免费试用期。
注意我不以任何方式隶属于 RedGate。
我已经发布了一个用于 sqlite 的工具,可以满足您的要求。它使用自定义差异驱动程序,利用 sqlite 项目工具“sqldiff”,将 UUID 作为主键,并保留 sqlite rowid。它仍处于 alpha 阶段,因此非常感谢您的反馈。
Postgres 和 mysql 比较棘手,因为二进制数据保存在多个文件中,如果您能够对其进行快照,甚至可能无效。
https://github.com/cannadayr/git-sqlite
没有原子性就无法做到这一点,如果不使用 pg_dump 或快照文件系统,就无法获得原子性。
我的 postgres 实例位于 zfs 上,我偶尔会对其进行快照。它几乎是即时且一致的。
我认为 X-Istence 走在正确的轨道上,但您可以对这个策略进行一些改进。首先,使用:
$pg_dump --schema ...
转储表、序列等并将此文件置于版本控制之下。您将使用它来分离分支之间的兼容性更改。
接下来,为包含应用程序运行所需的配置(应该可能跳过用户数据等)的表集执行数据转储,例如表单默认值和其他数据非用户可修改的数据。您可以使用以下方法有选择地执行此操作:
$pg_dump --table=.. <or> --exclude-table=..
这是一个好主意,因为在执行完整数据转储时,当您的数据库达到 100Mb+ 时,repo 会变得非常笨重。一个更好的主意是备份测试应用程序所需的更少量的数据集。但是,如果您的默认数据非常大,这仍然可能会导致问题。
如果您绝对需要在 repo 中放置完整备份,请考虑在源代码树之外的分支中进行。不过,参考匹配的 svn rev 的外部备份系统可能是最好的选择。
此外,我建议使用文本格式转储而不是二进制文件进行修订(至少对于模式),因为这些更容易区分。在签入之前,您始终可以压缩这些以节省空间。
最后,如果您还没有查看 postgres backup documentation,请查看。您评论备份“数据库”而不是转储的方式让我想知道您是否正在考虑基于文件系统的备份(请参阅第 23.2 节以了解警告)。
从本质上讲,您想要的可能类似于 Post Facto,它将数据库的版本存储在数据库中。检查此presentation。
该项目显然从未真正走到过任何地方,因此它可能不会立即为您提供帮助,但这是一个有趣的概念。我担心正确地做到这一点会非常困难,因为即使是版本 1 也必须正确处理所有细节才能让人们信任他们的工作。
我想做类似的事情,将我的数据库更改添加到我的版本控制系统中。
我将遵循 Vladimir Khorikov "Database versioning best practices" 在这篇文章中的想法。总之,我会
将其模式和参考数据存储在源代码控制系统中。
对于每次修改,我们将创建一个单独的 SQL 脚本,其中包含更改
万一有帮助!
这个问题已经得到了很好的回答,但我想用一个小建议来补充 X-Istence 和 Dana the Sane 的回答。
如果您需要某种程度的修订控制,比如说每天,您可以将表和架构的文本转储与执行增量备份的 rdiff-backup 之类的工具结合起来。优点是无需存储每日备份的快照,您只需存储与前一天的差异即可。
有了这个,您既拥有修订控制的优势,又不会浪费太多空间。
在任何情况下,直接在更改非常频繁的大型平面文件上使用 git 都不是一个好的解决方案。如果您的数据库变得太大,git 将开始在管理文件时遇到一些问题。
这是我在项目中尝试做的事情:
单独的数据和模式以及默认数据。
数据库配置存储在不受版本控制(.gitignore)的配置文件中
数据库默认值(用于设置新项目)是受版本控制的简单 SQL 文件。
对于数据库模式,在版本控制下创建一个数据库模式转储。
最常见的方法是使用包含 SQL 语句的更新脚本(ALTER Table.. 或 UPDATE)。您还需要在数据库中有一个位置保存当前版本的架构)
看看其他大型开源数据库项目(piwik,或者你最喜欢的 cms 系统),它们都使用 updatescripts (1.sql,2.sql,3.sh,4.php.5.sql)
但这是一项非常耗时的工作,您必须创建和测试更新脚本,并且您需要运行一个通用的更新脚本来比较版本并运行所有必要的更新脚本。
所以理论上(这就是我正在寻找的)你可以在每次更改后转储数据库模式(手动,conjob,git hooks(可能在提交之前))(并且仅在一些非常特殊的情况下创建更新脚本)
之后在您的通用更新脚本中(运行正常的更新脚本,对于特殊情况),然后比较模式(转储和当前数据库),然后自动生成必要的 ALTER 语句。已经有一些工具可以做到这一点,但还没有找到一个好的工具。
我在我的个人项目中所做的是,我将整个数据库存储到 Dropbox,然后指向 MAMP、WAMP 工作流程以从那里直接使用它。这样数据库在我需要进行一些开发时始终是最新的。但这仅适用于开发人员!实时站点正在使用自己的服务器来实现这一点! :)
在 git 版本控制下存储每个级别的数据库更改就像每次提交时推送您的整个数据库,并在每次拉取时恢复整个数据库。如果您的数据库很容易发生重大更改,并且您不能松动它们,您可以更新您的 pre_commit 和 post_merge 挂钩。我对我的一个项目做了同样的事情,你可以找到方向here。
我就是这样做的:
由于您可以自由选择数据库类型,因此请使用基于文件的数据库,例如 firebird。
创建一个模板数据库,其架构适合您的实际分支并将其存储在您的存储库中。
当以编程方式执行您的应用程序时,创建模板数据库的副本,将其存储在其他地方并使用该副本。
这样您就可以在没有数据的情况下将您的数据库模式置于版本控制之下。如果你改变你的架构,你只需要改变模板数据库
我们曾经在标准 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 中的所有流量指向一个占位符站点,创建一个 DB 转储,将工作目录从“live”指向“update” ',将所有新的 sql 文件执行到 mysql 中,并将流量重新指向正确的站点。当所有利益相关者在审查测试服务器后同意时,管理员从测试服务器到实时服务器做了同样的事情。之后,他将生产服务器上的 live 分支合并到所有服务器上的 master 分支,并重新设置所有 live 分支。开发人员自己负责重新调整他们的分支,但他们通常知道自己在做什么。
如果测试服务器出现问题,例如。合并有太多冲突,然后代码被还原(将工作分支指向“live”)并且从未执行过 sql 文件。在执行 sql 文件的那一刻,这在当时被认为是不可逆的操作。如果 SQL 文件不能正常工作,则使用 Dump 恢复 DB(并且开发人员告诉他们,提供经过不良测试的 SQL 文件)。
今天,我们维护了一个 sql-up 和 sql-down 文件夹,具有相同的文件名,开发人员必须在其中测试升级的 sql 文件是否可以同样降级。这最终可以使用 bash 脚本执行,但如果人眼不断监控升级过程,这是一个好主意。
这不是很好,但它可以管理。希望这能让您深入了解一个真实的、实用的、相对高可用性的网站。可能有点过时,但仍然遵循。
2019 年 8 月 26 日更新:
Netlify CMS 正在使用 GitHub 进行此操作,可以在此处找到一个示例实现,其中包含有关他们如何实现它的所有信息netlify-cms-backend-github
我说不要。数据可以随时更改。相反,您应该只在代码、架构和表定义(create database
和 create table
语句)中提交数据模型以及用于单元测试的示例数据。这有点像 Laravel 的做法,提交数据库迁移和种子。
我建议使用 neXtep(链接已删除 - 域被 NSFW 网站接管)来控制数据库的版本,它有一组很好的文档和论坛,解释了如何安装和遇到的错误。我已经为 postgreSQL 9.1 和 9.3 测试了它,我能够让它在 9.1 上工作,但对于 9.3 它似乎不起作用。
使用像 iBatis Migrations(manual、short tutorial video)这样的工具,它允许您在项目的整个生命周期内对数据库所做的更改进行版本控制,而不是数据库本身。
这使您可以有选择地将单个更改应用于不同的环境,保留更改日志以记录哪些更改在哪些环境中,创建脚本以应用更改 A 到 N,回滚更改等。
我想将整个数据库置于版本控制之下,我可以使用什么数据库引擎,以便将实际数据库置于版本控制之下而不是转储?
这不依赖于数据库引擎。 Microsoft SQL Server 有很多版本控制程序。我不认为这个问题可以用 git 解决,你必须使用 pgsql 特定的模式版本控制系统。不知道有没有这种东西……
不定期副业成功案例分享