バージョン管理システム、特に 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
リモート リポジトリにはフック フォルダーがあり、サンプルを含むいくつかのファイルが含まれています。
ls -1 /c/git/testdb.remote/hooks
フックは、特定のイベントが発生したときに実行されるスクリプトです。 Git にはクライアント側とサーバー側のフックがあります。クライアント側のフックは、コミットやマージなどの操作によってトリガーされます。サーバー側のフックは、プッシュされたコミットの受信などのネットワーク操作で実行されます。フックについては、ここで詳しく説明されています。ロジックを実装するにはさまざまなオプションがあります。 post-receiveサーバー側フックの使用例を示します。
フック フォルダー内に、「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:
- これは、サーバー上で実行された受信後スクリプトの出力です。
基本的な変更といえば、ファイルの追加、変更、削除が可能です。これらの変更をデータベースに適用する方法には、さまざまな方法があります。
2 番目のオプションを選択したと仮定すると、追加または変更されたファイルを実行する必要があります。ここで説明するように、パラメータ--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
「.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」ファイルが 4 つあります。
リポジトリに変更を加えます。
そして、 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 スクリプトを実行し、おそらく実稼働データベースでもいくつかのテストを実行します。
各ステップの結果を分析することで、任意の構成のパイプラインを作成できます。
もちろん、それぞれのアプローチには多くの利点と制限があります。 2 番目のアプローチでは、たとえばテーブルが作成されるまでテーブルにデータを挿入できないため、スクリプトの実行順序を保証する必要があります。また、スクリプトを再実行できること、つまり、作成中のオブジェクトがすでにデータベースに存在する場合、またはデータベースに追加するデータがすでに含まれている場合の状況を正しく処理できることを確認することも必要です。
バージョン管理システムを使用する場合、所定の形式のスクリプトの変更をさらに形式化する必要があるため、開発プロセスは少し複雑になります。ただし、インストール ファイルを使用すると、ある程度の柔軟性を実現できます。
ここで説明した手法の主な利点は、ほとんど労力をかけずにデータベースでのバージョン管理を実装できることと、 CI/CD パイプラインを実装できることです。
これが役立つかどうかを評価するには、次のことを自問することから始めます。実稼働環境でコードを直接記述する頻度はどれくらいですか?