GitLab にカスタムフックを設定する
Software Configuration Management (SCM)
これまで GitHub へプッシュしたリポジトリを GitLab へもバックアップ的にプッシュしてたのですけど、毎回両方にプッシュするのは面倒なので GitLab にプッシュすると GitHub へも転送されるようにしてみました。
以前にインストールしたバージョン管理システム こちら でGitLab を好んで使っているのですけど、この頃は GitHub を使う機会も増えてきました。
せっかくなので GitLab と GitHub の両方にアップして、片方をバックアップみたいな意味合いで使うようにしてたのですけど、そうなると両方に git push
をしないといけなくて若干煩わしいところがありました。
幸い、どちらでも根底で使われている Git
の カスタムフック
という仕組みを使うと、たとえば「プッシュしたタイミングで何かをする」みたいなことができるようだったので、これを使って片方のリポジトリにプッシュしたときに、もう片方のリポジトリへも自動でプッシュされるようにしてみました。
方針
まず、どちらのリポジトリにフックを仕掛けようか検討していたのですけど、とりあえず GitHub にカスタムフックを仕掛けられるのかわからなかったので、今回は GitLab のリポジトリにプッシュされたときに GitHub へプッシュするようにしてみます。
GitLab から GitHub へアクセスするための準備
そのために、まずは GitLab から GitHub へアップロードできるようにしました。
自分の GitLab 環境では git という名前のアカウントを使って運用されているので、まずは GitLab を入れたサーバーにそのアカウントでログインして、GitHub に接続するための秘密鍵と公開鍵を作成しました。
GitLab サーバーで鍵ペアを作成する
GitLab サーバーに接続したら、まずはホームディレクトリに .ssh
ディレクトリを作成して、そのパーミッションを 700 に設定しておきます。作成済みであればこの操作は不要です。
mkdir ~/.ssh
chmod 700 ~/.ssh
作成したらそのディレクトリに移動しておきます。
cd ~/
そして ssh-keygen
コマンドを使って秘密鍵と公開鍵のセットを作ります。
ssh-keygen -t rsa -b 4096
このときに鍵のファイル名を入力することになりますが、今回は id_github みたいな名前を入力しておくことにしました。
これで鍵が作成できました。
そうしたら GitLab から GitHub に接続しようとしたときにこの鍵が使われるように、次の内容で ~/.ssh/config
ファイルを作成しておくことにします。
host github.com
identityfile ~/.ssh/id_github
identitiesonly yes
公開鍵を GitHub に登録する
ここまでできたら、作成した公開鍵を GitHub に登録します。
公開鍵は、これまでの手順であれば ~/.ssh/id_github.pub
というファイルに保存されています。この中に次のような形式のテキストが記録されているので、それを GitHub に登録することになります。
ssh-rsa WNMHeKNzaC1yL0NLEAADAQABAAACAQC9WULdU9UQ6Zc2nU/+CeZhXyWNMHeK0vzXaAAcL4MPRiWooLS4Y1zAgleyEqR9Q6Zc2xgNSFHOhSCNVSRMwWNMHeKjMM4HaT7PJOKT7pKy1FtpEha+emTF4Q2A5vUwjKFP51lzMFKL0NLE7JV9NN3uFU9dUVj+2twxdoai+CeZhXQ6Zc2eK0vzXaAAcL4MPRiWooLS4Y1zAgleyEqR9YnEVWxgNSFHOhSCNVSRMwDaWKhNjMM4HaT7PJOKT7pKy1FtpEha+TZRxkpeQ6Zc2QHgo4WacNgyGdTj1x6OadFNVGPzQltr9IPBRAqdhLqZHHOrjy0ss7RWNMHeKdSHmvTm8MAlHhIxJM292WMRg8ciKFU5vUwVzypc2Vd4L0NLELPgouhcgXOCy3geTBozwvt6Fd/D4c9rtm0WNMHeKV5ywM5VpccXbQnWZfSFukFJdSJh2y76Hp5OZEvAcdddldZfAypPgKTr12WoWgQVrNfmeQ6Zc2WQ6Zc2bPV8xDQuG4HMuFJW8KfVl/3Ivea5vUwpn9a3zGmYKuSOXmTLbbJ91WI1u2ay5BotbFnyOWNMHeKqSwagjA42L6uPQxMLIKRAQ6Zc2YBqQ6Zc2w== tomohiro@xxxx.xx.xx
GitHub の Web ページにある Settings
を開いて、SSH keys
の画面を開きます。
そして Key
の欄にペーストして登録すれば、これでこの鍵に対応する秘密鍵を持っている人が接続できるようになりました。
GitLab にカスタムフックを登録する
それでは、GitLab のリポジトリにプッシュされたブランチを、そのまま GitHub にもプッシュするカスタムフックを作成してみます。
このようなフックを作成したい場合は、リポジトリにプッシュされたとき(Git サーバーがプッシュを受信したとき)に処理される pre-receive
フックと post-receive
フックあたりを使って追加の処理を実装することになるようでした。
リポジトリ毎にフックを作成する
これらのフックは、それを発動させたいリポジトリ毎に登録する必要があるようです。
通常の git であれば、この名前のファイルを .git/hooks
ディレクトリに作成して実行権限を与えれば動くらしいのですが、GitLab 環境では既にこれらのフックが登録されているようで、代わりに .git/custom_hooks
ディレクトリに作成する仕組みになっていました。
保存場所が変わる以外は、本来の Git と同じように作っていくことになる様子です。
なお、GitLab では Git リポジトリが ~/git-data/repositories/[USERNAME]
に保存されることになっているようです。
プッシュされたブランチを転送するスクリプトを作る
それでは、リポジトリへ転送されてきたブランチを、別のリポジトリへ転送するスクリプトを作成してみます。
今回のスクリプトでは、転送先のリポジトリをあらかじめ git remote add
で登録しておくことにします。このとき、リモートリポジトリ名は今回は 'github' としておきます。
作成するスクリプトは、今回は GitLab へブランチがプッシュされて、それらの内容をすべて受け取ったあとに実行される post-receive
を使うことにします。
このスクリプトは、プッシュされた Git 参照リストを標準入力で受け取る仕組みになっていて、このスクリプトが exit(0) で終了すればコミット完了、それ以外で終了したときはコミット却下という動きになります。処理の最中で標準出力に出力した内容は、そのまま push 処理時に出力されるメッセージの一環として表示されます。
標準入力で受け取れる値は「更新前のコミット情報」「更新後のコミット情報」「ブランチの参照情報」という 3 つがセットで渡ってきます。これが複数ある場合があるらしいので、それぞれをループで処理することにします。
GIT_REMOTE="github"
while read OLDREV NEWREV REFNAME
do
BRANCH=`git rev-parse --symbolic --abbrev-ref "${REFNAME}"`
echo "Push '${BRANCH}' branch to remote '${GIT_REMOTE}'"
git push --tag ${GIT_REMOTE} ${BRANCH}
done
このファイルを、目的のリポジトリ内の custom_hooks/post-receive
に作成して、実行可能なパーミッションを設定すれば、これで準備完了です。
chmod u+x custom_hooks/post-receive
動作を確認してみる
これで、先ほどのカスタムフックを登録したリポジトリにコミットをプッシュしてあげると、カスタムフックが実行されて、あらかじめ登録しておいたリモートリポジトリにも同じコミットがプッシュされるようになりました。
つまり、カスタムフックを設定したリポジトリが「リモートリポジトリ」として登録されている環境から、いつものようにプッシュすることで利用できます。
git push origin master
このようにすると、たとえば次のような出力がされて、プッシュ操作が行われます。ここの remote:
で記載されている内容が、カスタムフックで出力された文字列になるようです。
Counting objects: 59, done. Delta compression using up to 4 threads. Compressing objects: 100% (50/50), done. Writing objects: 100% (59/59), 31.79 KiB | 0 bytes/s, done. Total 59 (delta 12), reused 0 (delta 0) remote: Push 'master' branch to remote 'github' remote: To git@github.com:EZ-NET/ESSwim.git remote: * [new branch] master -> master To ssh://git@gitlab.ez-net.jp/tomohiro/ESSwim.git * [new branch] master -> master
このとき、もしカスタムフック側でプッシュできなかったりして失敗すると、そもそものこのリモートリポジトリへのプッシュ操作も取り消されることになるので、どちらか片方だけが更新されるみたいなことがなくて安心です。