Gitサーバーフック
- プラン: Free、Premium、Ultimate
- 提供形態: GitLab Self-Managed
GitLabサーバー上でサーバーフックはカスタムロジックを実行します。これにより、次のようなGit関連のタスクを実行できます:
- 特定のコミットポリシーを適用する。
- リポジトリの状態に基づいてタスクを実行する。
Gitサーバーフックは、pre-receive、post-receive、updateのGitサーバー側のフックを使用します。
GitLab管理者は、gitalyコマンドを使用してサーバーフックを設定します。このコマンドには、次のような機能もあります:
- Gitalyサーバーを起動する。
- いくつかのサブコマンドを提供する。
- Gitaly gRPC APIに接続する。
gitalyコマンドへのアクセス権がない場合は、サーバーフックの代替手段として以下を使用できます:
- Webhook。
- GitLab CI/CD。
- プッシュルール(ユーザーが設定可能なGitフックのインターフェース)。
GitLab Helmチャートのインスタンスについては、Gitalyチャートのグローバルサーバーフックに関する情報を参照してください。
Geoは、サーバーフックをセカンダリノードにレプリケートしません。
前提要件
- ストレージ名、Gitaly設定ファイルのパス(Linuxパッケージインスタンスではデフォルトは
/var/opt/gitlab/gitaly/config.toml)、リポジトリの相対パス。 - フックに必要な言語ランタイムとユーティリティが、Gitalyを実行する各サーバーにインストールされている必要があります。
リポジトリのサーバーフックを設定する
リポジトリのサーバーフックを設定するには、次の手順に従います:
カスタムフックを含むtarballを作成します:
サーバーフックが期待どおりに動作するようにコードを記述します。Gitサーバーフックは、任意のプログラミング言語で作成できます。言語の種類に応じて、スクリプトの先頭にシバンを記述してください。たとえば、Rubyでスクリプトを記述する場合、シバンはおそらく
#!/usr/bin/env rubyとなります。- 単一のサーバーフックを作成するには、フックタイプに対応する名前のファイルを作成します。たとえば、
pre-receiveサーバーフックの場合、ファイル名は拡張子なしでpre-receiveにします。 - 複数のサーバーフックを作成するには、フックタイプに対応する名前のディレクトリを作成します。たとえば、
pre-receiveサーバーフックの場合、ディレクトリ名はpre-receive.dにします。そのディレクトリに、フックのファイルを配置します。
- 単一のサーバーフックを作成するには、フックタイプに対応する名前のファイルを作成します。たとえば、
サーバーフックファイルが実行可能であり、バックアップファイルのパターン(
*~)に一致していないことを確認します。サーバーフックは、tarballのルートにあるcustom_hooksディレクトリに配置されている必要があります。tarコマンドを使用して、カスタムフックアーカイブを作成します。例:
tar -cf custom_hooks.tar custom_hooks。
必要なオプションを指定して
hooks setサブコマンドを実行し、リポジトリのGitフックを設定します。次に例を示します:cat custom_hooks.tar | sudo -u git -- /opt/gitlab/embedded/bin/gitaly hooks set --storage <storage> --repository <relative path> --config <config path>ノードに接続するには、そのノードの有効なGitaly設定のパスを
--configフラグで指定する必要があります。カスタムフックのtarballは、
stdinを通じて渡す必要があります。次に例を示します:cat custom_hooks.tar | sudo -u git -- /opt/gitlab/embedded/bin/gitaly hooks set --storage <storage> --repository <relative path> --config <config path>
Gitaly Cluster (Praefect)を使用している場合は、すべてのGitalyノードで
hooks setサブコマンドを実行する必要があります。
サーバーフックコードが正しく実装されていれば、次回Gitフックがトリガーされたときにそのコードが実行されるはずです。
Gitaly Cluster (Praefect)のサーバーフック
Gitaly Clusterを使用している場合、単一のリポジトリがPraefect内の複数のGitalyストレージにレプリケートされることがあります。そのため、フックスクリプトは、リポジトリのレプリカが存在するすべてのGitalyノードにコピーする必要があります。これを実現するには、該当バージョンに対応したカスタムリポジトリフックの設定手順に従い、各ストレージに対して同様の作業を繰り返します。
スクリプトのコピー先は、リポジトリの保存場所によって異なります。新しいリポジトリは、ハッシュストレージパスではなく、Praefectによって生成されたレプリカパスを使用して作成されます。レプリカパスを特定するには、-relative-pathオプションを使用して、予期されるGitLabのハッシュストレージパスを指定して、Praefectリポジトリメタデータをクエリします。
すべてのリポジトリに適用されるグローバルサーバーフックを作成する
すべてのリポジトリに適用されるGitフックを作成するには、グローバルサーバーフックを設定します。グローバルサーバーフックは、以下にも適用されます:
- プロジェクトおよびグループウィキのWikiリポジトリ。これらのストレージディレクトリ名は、
<id>.wiki.gitという形式になります。 - プロジェクトの設計管理リポジトリ。これらのストレージディレクトリ名は、
<id>.design.gitという形式になります。
サーバーフックのディレクトリを選択する
グローバルサーバーフックを作成する前に、使用するディレクトリを選択する必要があります。
このディレクトリは、gitaly['configuration'][:hooks][:custom_hooks_dir]のgitlab.rbで設定します。次のいずれかの方法があります:
- コメントアウトを解除して、
/var/opt/gitlab/gitaly/custom_hooksディレクトリのデフォルトの提案を使用する。 - 独自の設定を追加する。
- ディレクトリは
[hooks]セクションのgitaly/config.tomlで設定します。ただし、gitaly/config.tomlの値が空白または存在しない場合、GitLabはgitlab-shell/config.ymlのcustom_hooks_dirの値を優先します。 - デフォルトのディレクトリは
/home/git/gitlab-shell/hooksです。
グローバルサーバーフックを作成する
すべてのリポジトリに適用されるグローバルサーバーフックを作成するには、次の手順に従います:
- GitLabサーバーで、設定済みのグローバルサーバーフック用ディレクトリに移動します。
- 設定済みのグローバルサーバーフック用ディレクトリで、フックタイプに対応する名前のディレクトリを作成します。たとえば、
pre-receiveサーバーフックの場合、ディレクトリ名はpre-receive.dにします。 - この新しいディレクトリ内に、サーバーフックを追加します。Gitサーバーフックは、任意のプログラミング言語で作成できます。言語の種類に応じて、スクリプトの先頭にシバン (
#!) を記述してください。たとえば、Rubyでスクリプトを記述する場合、シバンはおそらく#!/usr/bin/env rubyとなります。 - フックファイルを実行可能にし、Gitユーザーが所有していること、およびバックアップファイルのパターン(
*~)に一致していないことを確認します。
サーバーフックコードが正しく実装されていれば、次回Gitフックがトリガーされたときにそのコードが実行されるはずです。フックは、フックタイプ別サブディレクトリ内で、ファイル名のアルファベット順に実行されます。
リポジトリのサーバーフックを削除する
サーバーフックを削除するには、空のtarballをhook setに渡して、リポジトリにフックを含めないように指示します。次に例を示します:
cat empty_hooks.tar | sudo -u git -- /opt/gitlab/embedded/bin/gitaly hooks set --storage <storage> --repository <relative path> --config <config path>チェーンされたサーバーフック
GitLabではサーバーフックをチェーンで実行できます。GitLabは、次の順序でサーバーフックを検索し、実行します:
- GitLabに組み込まれているサーバーフック。これらのサーバーフックをユーザーがカスタマイズすることはできません。
<project>.git/custom_hooks/<hook_name>: プロジェクト単位のフック。この場所は下位互換性のために保持されています。<project>.git/custom_hooks/<hook_name>.d/*: プロジェクト単位のフックの場所。<custom_hooks_dir>/<hook_name>.d/*: エディタバックアップファイルを除く、すべての実行可能なグローバルフックファイルの場所。
サーバーフックディレクトリ内で、フックは次のように動作します:
- ファイル名のアルファベット順に実行されます。
- ゼロ以外の値でフックが終了すると、実行を停止します。
サーバーフックで使用可能な環境変数
任意の環境変数をサーバーフックに渡すことはできますが、サポートされている環境変数のみを使用する必要があります。
次のGitLab環境変数は、すべてのサーバーフックでサポートされています:
| 環境変数 | 説明 |
|---|---|
GL_ID | プッシュを開始したユーザーまたはSSHキーのGitLab識別子。例えば、user-2234やkey-4です。 |
GL_PROJECT_PATH | GitLabプロジェクトのパス。 |
GL_PROTOCOL | この変更に使用するプロトコル。次のいずれかになります: http(HTTPを使用したGit push)、ssh(SSHを使用したGit push)、web(その他すべての操作)。 |
GL_REPOSITORY | project-のプレフィックスが付いたGitLabプロジェクトID。例:project-1234 |
GL_USERNAME | プッシュを開始したユーザーのGitLabのユーザー名。 |
次のGit環境変数は、pre-receiveおよびpost-receiveサーバーフックでサポートされています:
| 環境変数 | 説明 |
|---|---|
GIT_ALTERNATE_OBJECT_DIRECTORIES | 検疫環境における代替オブジェクトディレクトリ。 |
GIT_OBJECT_DIRECTORY | 検疫環境におけるGitLabプロジェクトのパス。 |
GIT_PUSH_OPTION_COUNT | プッシュオプションの数。 |
GIT_PUSH_OPTION_<i> | 特定のプッシュオプションの値。<i>は、GIT_PUSH_OPTION_COUNTで定義された値よりも1つ少ない0からになります。 |
カスタムエラーメッセージ
サーバーフックがプッシュを拒否した場合、プッシュが拒否された理由と問題の修正方法をユーザーが理解できるように、明確なエラーメッセージを提供します。カスタムエラーメッセージは、フックがプッシュを拒否すると、GitLab UIおよびユーザーのターミナルに表示されます。
カスタムエラーメッセージがない場合、ユーザーには(pre-receive hook declined)のような一般的なメッセージのみが表示されます。明確なエラーメッセージは、ユーザーに役立ちます:
- プッシュが拒否された理由を理解する。
- 管理者に連絡せずに問題を修正する。
- サポートリクエストを削減する。
カスタムエラーメッセージを表示するには、次のようなスクリプトを使用します:
- カスタムエラーメッセージをスクリプトの
stdoutまたはstderrに送信する。 - 各メッセージの先頭に
GL-HOOK-ERR:を付加する(プレフィックスの前に他の文字を含めない)。
次に例を示します:
# Bad: Generic message
echo "GL-HOOK-ERR: Commit rejected.";
# Good: Specific message with action
echo "GL-HOOK-ERR: Commit rejected: Commit message must include an issue reference (for example, #1234).";関連トピック
トラブルシューティング
Gitサーバーフックを使用する際に、次の問題が発生することがあります。
エラー: pre-receive hook declined
ユーザーがGitLabリポジトリにプッシュすると、(pre-receive hook declined)を含むエラーメッセージが表示されることがあります。次に例を示します:
! [remote rejected] main (pre-receive hook declined)
error: failed to push some refs to 'https://gitlab.example.com/group/project'このエラーは、事前受信フックがプッシュを拒否したことを示します。事前受信フックは、参照がリポジトリ内で更新される前に実行されます。Gitには、プッシュを拒否できる3つのサーバーサイドフックが用意されています:
pre-receive: すべての参照が更新される前に実行されます。プッシュ全体を拒否できます。update: 更新されるブランチごとに1回実行されます。個々のブランチを拒否できます。post-receive: すべての参照が更新された後に実行されます。プッシュを拒否できませんが、フックが失敗した場合、エラーが発生する可能性があります。
(pre-receive hook declined)エラーは通常、pre-receiveまたはupdateフックから発生します。問題を特定するには:
(pre-receive hook declined)メッセージの直前の出力を確認します。この出力には、プッシュが拒否された理由に関する情報が含まれていることがよくあります。次に例を示します:remote: GitLab: The default branch of a project cannot be deleted. ! [remote rejected] main (pre-receive hook declined)フックが失敗した理由の詳細については、Gitalyログを確認してください:
sudo grep PreReceiveHook /var/log/gitlab/gitaly/current | jq .リポジトリにカスタムサーバーフックが構成されている場合は、カスタムフックコードに問題がないか確認してください。
事前受信フックの失敗の一般的な原因を以下に示します:
- デフォルトブランチ保護: デフォルトブランチを削除または強制的に更新するプッシュは拒否されます。これは、ソースリポジトリのデフォルトブランチがターゲットリポジトリと異なる場合に
git push --mirrorで発生します。 - プッシュルール: プッシュは、コミットメッセージの要件、ファイルサイズの制限、作成者のメール制限など、構成済みのプッシュルールに違反しています。
- カスタムサーバーフック: カスタムサーバーフックスクリプトがプッシュを拒否しました。カスタムフックコードとエラーメッセージをレビューします。
- タイムアウト: フックの実行に時間がかかりすぎて、強制終了されました。タイムアウトエラーについては、Gitalyログを確認してください。
- LFSオブジェクト: リポジトリに必要なGit LFSオブジェクトが見つかりません。
フックの失敗をユーザーが理解できるように、カスタムエラーメッセージを使用して、プッシュが拒否された理由に関する明確なフィードバックを提供します。カスタムエラーメッセージは、GitLab UIおよびユーザーのターミナルに表示されます。