ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

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

我的数据库是 PostgreSQL

编辑:

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

一定有更好的方法。

更新:

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

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

sqlite 对 git 友好吗?

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

编辑2:

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

老实说,如果我要引入架构更改并且必须同时处理多个开发分支,我只会制作数据库的副本......开发数据库应该足够小来做到这一点。我会认为任何试图聪明并进行数据库更改的系统只是因为我怀疑地更改了源分支。如果我只是克隆我的工作区并在一个位置有一个分支,另一个在新的位置,我还想确保事情能够继续工作。
如果您将用于初始化数据库的脚本(及其组件)视为受版本控制的工件,那么“备份”似乎并不是一件坏事。如果您在激进分支中更改数据库架构,则需要使用数据更新初始化数据库的脚本。
查看我对完全执行此操作的软件的回答:stackoverflow.com/a/28123546/1662984

X
X-Istence

进行数据库转储,然后进行版本控制。这样它是一个平面文本文件。

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

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


PostGreSQL 数据库文件是二进制文件,请随意将它们放在您的 git 存储库中,您将无法对它们进行任何差异,任何更改很可能会更改整个数据库,因此您现在必须发送完整的数据库通过电线连接到您的 git 存储库并存储它。这是低效、缓慢的,并且非常难以使用。另外,我不确定在没有 VACUUM 和关闭 PostgreSQL 以制作副本的情况下存储在磁盘上的数据库文件是否“稳定”,因为所有数据总是正确的,因此可能会给您留下损坏的数据。
嗯,我明白了!那么,有没有对 git 更友好的数据库系统?
这种类型的解决方案非常标准,架构实际上是源代码。
请注意,如果您有带密码的外部数据包装器连接,则这些密码将存储在架构中。因此,如果您将转储放入版本控制中,那么这些密码最终会出现在版本控制中。
对我们为什么不版本二进制文件缺乏理解有点恼火(为了提高效率,几乎每个活动的数据库都是二进制文件)。简短的回答:它们不会以干净的方式更改源文件,因此维护一长串补丁程序效率低下。如果您想对数据库模式进行版本控制并且不想手动转储,请使用 git 挂钩(或您最喜欢的 vcs 中的挂钩)让它自动从数据库服务器请求模式转储。然后你会有一些一致的东西,你的 vcs 可以区分。
C
Community

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

复制数据库(模式和数据)。

在 new-major-changes 的分支中,只需更改项目配置以使用新的重复数据库。

这样我就可以切换分支而不用担心数据库模式的变化。

编辑:

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


git hook 根据分支名称从模板创建数据库,
这就是我所做的,我还在数据库变量的包含文件中添加了一个 IP 检查行,这样如果我不小心将“错误”分支的文件上传到实时服务器,就不会中断。
所以几乎每个分支都有自己的数据库,对吧? 🤔
T
Thomas Fenzl

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


Liguibase 的最佳实践建议将模式创建脚本保留为一组按顺序运行的顺序脚本。虽然这是一个很好的最佳实践,但我看不出如果没有中央存储库(非 GIT)它会如何工作。
好吧,如果你小心你的 id= 和 author= 标签,它会在 git 上正常工作。理论上,每个用户都有自己的作者条目(GOOD),如果你用 id= 做一些合理的事情,比如 YYYYMMDD_REV,那么你就很好了。即使使用 git,对于给定的项目,大多数人都有一个“中央仓库”。 99% 的人没有“中心”的东西。同样,Liquibase 文件只是计划文本 XML-ish 文件,带有一组命令以针对给定的数据库(或一组)执行。在实践中,有 99% 的项目可能会出现 0 个问题,即使是 DVCS 也是如此。
+1 对于这个答案。这是我们在几个项目中使用的。 ID 只需要在一个 xml 文件中是唯一的。如果您从正在实施的用例中命名 id,它们就足够独特了。您必须小心不要修改已应用的变更集,否则您将收到校验和错误。
T
Tails

Irmin(分支+时间旅行)

Flur.ee(不可变+时间旅行+图查询)

Crux DB(时间旅行+查询)

TerminusDB(不可变+分支+时间旅行+图查询!)

DoltDB(分支+时间旅行+SQL查询)

Quadrable(分支+远程状态验证)

EdgeDB(不是实时旅行,而是由编译器在架构更改后派生的迁移)

Migra(Postgres 模式/数据的差异。自动生成迁移脚本,自动同步数据库状态)

ImmuDB(不可变+时间旅行)


OrbitDB 无服务器、分布式、点对点。可用于构建联合可变存储
我会说 OrbitDB 是一个荣誉奖,但不满足版本控制要求,除非确保收集文档历史的所有 CRDT。
是的...版本控制需要在 p2p 网络中达成共识。示例:BigchainDB
s
sibaz

我遇到了这个问题,因为我遇到了类似的问题,其中一些近似于基于数据库的目录结构,存储“文件”,我需要 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 的内部差异和合并工具。我会更新这个答案,因为我想出了一个更好的问题解决方案,但在我的情况下,我希望只需要管理数据更改,到目前为止,基于数据库的文件存储可能会发生变化,所以我的解决方案可能不是您所需要的。


H
Hakan Deryal

有一个名为 Migrations under Doctrine 的伟大项目就是为此目的而构建的。

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

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


操作!您的链接已损坏...也许您的意思是:github.com/doctrine/migrations
这里是在 Symfony2 中集成学说迁移的捆绑包的文档:symfony.com/doc/master/bundles/DoctrineMigrationsBundle/…
C
CShark

看看 RedGate SQL 源代码控制。

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

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

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

注意我不以任何方式隶属于 RedGate。


c
cannadayr

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

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

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


好像您让 git 按原样存储二进制数据。相反,可以使用清洁/涂抹过滤器来存储转储。有 some scripts 可以做到这一点。
体面的方法,除非您区分两个数据库状态,否则您正在执行转储的文本差异。通过使用 sqldiff 作为自定义差异驱动程序,您可以获得将数据库变异到下一个状态的实际命令。
在尝试之前,我想看看一些例子。有教程/展示/演示吗?
签出 github.com/cannadayr/git-sqlite#usage-guide 。如果您还有任何问题,请给我发电子邮件(请参阅我的 github 个人资料)。
D
Dustin

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

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


D
Dana the Sane

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

$pg_dump --schema ... 

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

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

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

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

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

此外,我建议使用文本格式转储而不是二进制文件进行修订(至少对于模式),因为这些更容易区分。在签入之前,您始终可以压缩这些以节省空间。

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


转储不只是备份吗?
是的,但您可以将其还原到备用数据库并在那里进行修改。
P
Peter Eisentraut

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

该项目显然从未真正走到过任何地方,因此它可能不会立即为您提供帮助,但这是一个有趣的概念。我担心正确地做到这一点会非常困难,因为即使是版本 1 也必须正确处理所有细节才能让人们信任他们的工作。


C
Ciges

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

我将遵循 Vladimir Khorikov "Database versioning best practices" 在这篇文章中的想法。总之,我会

将其模式和参考数据存储在源代码控制系统中。

对于每次修改,我们将创建一个单独的 SQL 脚本,其中包含更改

万一有帮助!


u
unode

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

如果您需要某种程度的修订控制,比如说每天,您可以将表和架构的文本转储与执行增量备份的 rdiff-backup 之类的工具结合起来。优点是无需存储每日备份的快照,您只需存储与前一天的差异即可。

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

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


k
key_

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

单独的数据和模式以及默认数据。

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

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

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

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

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

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

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

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


M
Marko

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


A
AkiShankar

在 git 版本控制下存储每个级别的数据库更改就像每次提交时推送您的整个数据库,并在每次拉取时恢复整个数据库。如果您的数据库很容易发生重大更改,并且您不能松动它们,您可以更新您的 pre_commitpost_merge 挂钩。我对我的一个项目做了同样的事情,你可以找到方向here


R
RomCoo

我就是这样做的:

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

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

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

这样您就可以在没有数据的情况下将您的数据库模式置于版本控制之下。如果你改变你的架构,你只需要改变模板数据库


F
Florian Mertens

我们曾经在标准 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 脚本执行,但如果人眼不断监控升级过程,这是一个好主意。

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


C
Ceddy Muhoza

2019 年 8 月 26 日更新:

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


O
OzzyTheGiant

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


M
Morty

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


@Nickolay 是的,它似乎已经停产了。作为替代方案,您为什么不试试 Skitch,您会在这里找到它sqitch.org
m
matt b

使用像 iBatis Migrations(manualshort tutorial video)这样的工具,它允许您在项目的整个生命周期内对数据库所做的更改进行版本控制,而不是数据库本身。

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


i
inf3rno

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

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


您真的应该看看 klonio 它是为版本控制数据库量身定制的(目前支持 Mongo 和 MySQL)。仍处于测试阶段,但似乎很有希望。