Gitの特定ブランチへのコミットをLefthookで防止する
はじめに
GitHubのルールセットを活用することで特定ブランチ、例えばmain
やmaster
ブランチへのプッシュを防止することができます。しかし、この機能は
ルールセットは、GitHub Free と GitHub Free の Organization のパブリック リポジトリ、GitHub Pro、GitHub Team、GitHub Enterprise Cloud のパブリックとプライベートのリポジトリで利用できます。
https://docs.github.com/ja/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets
とある通り、GitHub Freeを利用しているプライベートリポジトリでは適用することができません。そこで、この記事ではGitのフック機能を利用することで特定のブランチへのコミットを防止します。
フックの管理にLefthookを利用しています。これにより、commitlint
等の他のフックとも容易に共存させることができます。
この記事のゴール
-
main
ブランチへのコミットを防止する - ただし、
[commit-main]
がコミットメッセージに含まれる場合のみ許可する
フックの設定
各言語のパッケージマネージャー等を利用してインストールを完了させてください。
続いて、以下の2ファイルを作成します。
#!/bin/sh
COMMIT_MSG_FILE=$1
if ! grep -q "\[commit-main\]" "$COMMIT_MSG_FILE"; then
echo "Error: You cannot commit to the main branch without the [commit-main] tag in the commit message."
exit 1
fi
sed -i "s/\[commit-main\]//g" "$COMMIT_MSG_FILE"
commit-msg:
scripts:
"prevent-main-commit.sh":
runner: bash
only:
- ref: main
.lefthook/commit-msg/prevent-main-commit.sh
が処理の本体です。$1
には、commit-msg
フックを実行したときにコミットしようとしているコミットメッセージが記載されたファイルのパスが代入されています。そのファイルの内容を読み取り、[commit-main]
が含まれていなければメッセージを表示してコード1で終了します。含まれている場合には、それを取り除くようにコミットメッセージを書き換えます。終了コードが0以外になると、Gitがコミットを中止する仕様を利用しています。
lefthook.yml
では、このスクリプトを実行方法とブランチの指定を定義しています。
なお、マージコミットはこの制限の対象外とする場合、
"prevent-main-commit.sh":
runner: bash
only:
- ref: main
+ skip: merge
のようにskip
設定を追加します。
また、今回はコミット時に制限を適用していますが、GitHubの挙動のようにプッシュ時に制限を適用するには、commit-msg
フックの代わりにpre-push
フックを使うなどの変更が必要です。
Discussion