paint-brush
将 Git Hooks 与 MySQL 结合使用经过@yuridanilov
4,692 讀數
4,692 讀數

将 Git Hooks 与 MySQL 结合使用

经过 Yuri Danilov7m2023/09/30
Read on Terminal Reader

太長; 讀書

创建测试数据库 接收后创建 git hook 在推送时执行 SQL 脚本
featured image - 将 Git Hooks 与 MySQL 结合使用
Yuri Danilov HackerNoon profile picture
0-item
1-item

版本控制系统,尤其是 Git,是跟踪代码更改、与团队协作以及确保代码库稳定性的重要工具。虽然 Git 主要是为源代码设计的,但您也可以将其与MySQL数据库结合使用,以进行版本控制和架构更改管理。


在本文中,我们将探讨如何使用 Git 挂钩将 Git 与 MySQL 集成以进行版本控制,并以指南格式提供具体示例。清单中给出的所有脚本功能齐全且完整。您可以在测试环境中按顺序重现它们。


首先,我们创建一个测试数据库和用户:

 create database testdb_remote; create user 'user_remote'@'localhost' identified WITH mysql_native_password by 'remote123'; grant all on testdb_remote.* to 'user_remote'@'localhost'; 


创建测试数据库


接下来,我们将创建一个远程存储库。这可以是任何远程服务器上的存储库,但为了简单起见,我们将在本地创建它。为了方便执行命令,我使用git bash。我的本地机器已经有一个 git 文件夹,所以我使用它:

 cd /c/git mkdir testdb.remote cd testdb.remote git init --bare 


创建远程仓库

并创建一个本地存储库作为远程存储库的克隆:

 cd /c/git git clone /c/git/testdb.remote testdb.local cd testdb.local git ls-files 


创建本地存储库


存储库中没有文件;让我们创建一个并将更改推送到远程存储库:

 echo "Test DB repo" > readme.md git status git add . git commit -m "1st commit" git push 


第一推


让我们检查一下远程存储库的内容:

 cd /c/git/testdb.remote git ls-tree --full-tree -r HEAD 


远程仓库中的文件


远程存储库中有一个 hooks 文件夹,其中包含几个带有示例的文件:

 ls -1 /c/git/testdb.remote/hooks 


样品挂钩


挂钩是当特定事件发生时执行的脚本。 Git 有客户端和服务器端挂钩。客户端钩子由提交和合并等操作触发。服务器端挂钩在网络操作上运行,例如接收推送的提交。这里详细描述了钩子。实现逻辑有不同的选择;我将给出一个使用post-receive服务器端挂钩的示例。


在 hooks 文件夹中,我们需要创建一个名为“post-receive”的文件,这是一个常规的 bash 脚本:

 #!/bin/sh while read oval nval ref do echo List of files changed in the commit: git diff --name-only $oval $nval done


每当推送成功完成时,上述脚本就会在服务器上执行,并输出已修改文件的列表。让我们通过在 readme.md 中添加一行并将更改推送到远程存储库来检查它是如何工作的:

 cd /c/git/testdb.local echo "New line" >> readme.md git add . git commit -m "Line added" git push 


测试接收后挂钩脚本


您可以看到,执行 git push 命令时,输出现在包含以remote: - 这是在服务器上执行的 post-receive 脚本的输出。

说到基本更改,可以添加、修改和删除文件。您可以采用不同的方法将这些更改应用到数据库:


  1. 仅在添加新文件时才对数据库进行更改。在这种情况下,您可以将特定任务的所有更改保存在单个文件中。该文件可能包含错误跟踪系统中的任务名称。这在开发过程中可能不太方便,但这样的改变更容易处理。
  2. 在存储库中为每个对象(表、过程)保留一个单独的文件,并在更改或添加文件时将更改应用到数据库。
  3. 更全面的方法是为每个任务(更改请求)创建一个单独的文件夹,并将应作为给定版本安装的一部分执行的文件放入其中。同时,创建一个附加文件来描述文件列表以及它们的安装顺序。这种方法更加灵活,但同时对于开发和管道实现来说也更加复杂。


假设您选择了第二个选项,那么您需要执行已添加或更改的文件。我们可以通过添加参数--diff-filter=AM来过滤此处描述的此类文件:

 #!/bin/sh while read oval nval ref do echo List of files added or changed in the commit: git diff --name-only --diff-filter=AM $oval $nval done


添加几个文件,并再次更改readme.md:

 echo "SELECT 1;" > test1.sql echo "SELECT 2;" > test2.sql echo "SELECT 3;" > test3.sql echo "New line 2" >> readme.md git add . git commit -m "New files" git push


挂钩脚本的输出包含 4 个文件:

所有已更改文件的列表


我们编辑 test1.sql 和 readme.md 文件,删除 test2.sql,并添加另一个文件:

 echo "SELECT 11;" > test1.sql echo "New line 2" >> readme.md rm test2.sql echo "SELECT 4;" > test4.sql git add . git commit -m "Modify, remove and add" git push


仅显示修改和添加的文件:

仅添加或更改的文件


我们的目标是在每次成功推送后执行SQL脚本,因此我们需要过滤仅此类型的文件;在我们的例子中,我们将要求它们都必须具有“.sql”扩展名。要进行过滤,请将参数-- "*.sql"添加到git diff命令中:

 #!/bin/sh while read oval nval ref do echo List of files added or changed in the commit: git diff --name-only --diff-filter=AM $oval $nval -- "*.sql" done


要执行脚本,我们还必须能够连接到数据库。为此,我们将创建凭据并测试连接:

 mysql_config_editor set --login-path=testdb_remote --host=localhost --port=3306 --user=user_remote --password mysql --login-path=testdb_remote --database=testdb_remote 


为 MySQL 创建信用


修改我们的脚本以迭代“.sql”文件,执行每个文件,并检查结果。我们还需要对列表输出进行排序,以按所需的顺序执行文件。使用 git show 命令,我们显示 SQL 脚本的内容,并将其通过管道传递给 MySQL 执行

变量“$?”如果 SQL 脚本执行成功,则包含 0;如果出现错误,则包含另一个值:

 #!/bin/sh while read oval nval ref do echo List of files added or changed in the commit: for file in $(git diff --name-only --diff-filter=AM $oval $nval -- "*.sql" | sort); do git show master:${file} | mysql --login-path=testdb_remote --database=testdb_remote echo "FILE: ${file} - result $?" done done


再执行一项测试 - 删除所有先前创建的“.sql”文件并为以下内容创建脚本:


  • 表创建
  • 向表中插入数据
  • 创建从表接收数据的过程
  • 包含错误的脚本


我们还需要为每个文件名添加前缀(1_、2_ 等),以确保文件的所需执行顺序:

 rm *.sql echo "DB Initialization" >> readme.md echo " DROP TABLE IF EXISTS customers; CREATE TABLE customers ( id int UNSIGNED NOT NULL AUTO_INCREMENT, name varchar(255) DEFAULT NULL, PRIMARY KEY (id) ); " > 1_customers.sql echo " INSERT INTO customers (id, name) VALUES (1, 'John Doe'), (2, 'Jane Smith') AS new ON DUPLICATE KEY UPDATE customers.name = new.name; " > 2_customers_init.sql echo " DROP PROCEDURE IF EXISTS get_customer; DELIMITER $$ CREATE PROCEDURE get_customer(IN customer_id int UNSIGNED) BEGIN SELECT c.id, c.name FROM customers c WHERE c.id = customer_id; END $$ " > 3_get_customer.sql echo "SELECT FROM customers;" > 4_error_select.sql ls -1


所以我们有四个“.sql”文件需要执行:

文件列表

我们对存储库进行更改:

仅执行 SQL 文件


并且我们看到,当执行git push时,文件是顺序执行的,并显示每个文件的执行结果(MySQL命令退出代码)。文件“4_error_select.sql”包含语法错误,因此其执行结果为1。


最后,让我们检查一下数据库中的内容:

 mysql --login-path=testdb_remote --database=testdb_remote show tables; call get_customer(1); call get_customer(2); 


测试数据库中创建的对象


如您所见,表和过程是在远程数据库中创建的。该过程成功执行并返回数据。


为了提高挂钩脚本输出的可读性,您可以抑制 MySQL CLI 输出或将其重定向到日志文件。您还可以分析MySQL命令执行的结果,并向钩子脚本添加更多逻辑。


例如,您可以在测试数据库上执行 SQL 脚本,然后对其运行一些测试(如我在此处所述)。如果测试在测试数据库上成功完成,请在生产数据库上运行 SQL 脚本,并可能对其运行一些测试。

通过分析每个步骤的结果,您可以创建任何配置的管道。


当然,每种方法都有许多优点和局限性。使用第二种方法,需要确保脚本的执行顺序,因为例如,在创建表之前我们无法将数据插入到表中。还需要确保可以重新执行脚本,即正确处理正在创建的对象已在数据库中或数据库已包含要添加的数据的情况。


当使用版本控制系统时,开发过程变得稍微复杂一些,因为需要另外形式化预定格式的脚本中的更改。但是,您可以通过使用安装文件来实现一定的灵活性。


所描述技术的主要优点是在数据库中轻松实现版本控制,以及实现CI/CD 管道的能力。

要评估这对您是否有用,您可以首先问自己:您直接在生产中编写代码的频率如何?