1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

commit と push 周りの GitHooks を勉強しただけ

Last updated at Posted at 2021-08-16

この記事は?

Git Hooks での、コミット生成の制御と push 受け取りの制御について学んだのでメモ。
Git の運用ルール (コミットメッセージやブランチ名のルール等) を、スクリプトで規制したい、という方に役立てられれば幸いです。

Git の基礎的な使い方が分かっていること、シェルスクリプトがある程度読める・書けることを前提に話を進めます。

Git Hooks とは?

Git Hooks というのは、Git で何らかのアクション (例: コミットを作成, マージ, リモートへ Push 等) が発生した際に、特定のプログラム (主にシェルスクリプト) を実行する仕組みです。
検出できるアクションはいくつかあります。

こちらの記事で図に分けて説明してくださっています。

これら全てを活用するのは、本格的で大規模な開発であるときと思います。
この記事では、コミット関係 (クライアントサイド) と、push 受け取り関係 (サーバサイド) を扱います。

Git Hooks スクリプトの置き場所

クライアントサイド (ローカルリポジトリ) では、リポジトリのルート上から.git/hooks/ (隠しフォルダ) に。
サーバサイド (リモートリポジトリ) では、リポジトリのルート上からhooks/に。
このディレクトリに、各アクションに対応するファイル名で、スクリプトを配置します。

ls .git/hooks/
# applypatch-msg.sample*      pre-merge-commit.sample*
# commit-msg.sample*          pre-push.sample*
# fsmonitor-watchman.sample*  pre-rebase.sample*
# post-update.sample*         pre-receive.sample*
# pre-applypatch.sample*      prepare-commit-msg.sample*
# pre-commit.sample*          update.sample*

デフォルトでは、.sampleと書かれたサンプルのプログラム (シェルスクリプト) が配置されています。
Git Hooks を動作させる際には、対応させるアクションのファイル名で、.sampleを付けず、プログラムを配置します。(実行権限の付与もお忘れなく。)

また、リモートリポジトリ上のhooks/と、ローカルリポジトリ上の.git/hooks/は、クローン (同期) されません。
そのため、開発者全員に特定のルールに沿った Git Hooks を使用させるには、別途設定をさせる必要があります。
(一見すると不便な仕様に見えるかもしれませんが、悪意あるスクリプトを実行させないためでしょう。特に、GitHub 等で公開されているオープンなリポジトリでは。)

コミット関係 (クライアントサイド)

コミットに関する Git Hooks は、全部で 4つあります。
Git でのコミット生成の動作と合わせて説明すると、以下のように呼び出されます。

  1. git commitが実行される
  2. --- pre-commitが実行される
  3. (1. で-m "<message>"オプションがあったなら、<message>が書き込まれた) .git/COMMIT_EDITMSGが生成される
  4. --- prepare-commit-msgが実行される
  5. (1. で-m <message>オプションが無かったなら) .git/COMMIT_EDITMSGの編集が開始される
  6. --- commit-msgが実行される
  7. コミットが生成される
  8. --- post-commitが実行される

Hook-Commit.png

pre-commit prepare-commit-msg commit-msgにおいて、exit 1等のように、0 以外の返り値が発生した場合、その時点でコミットの動作が中止 (reject) されます。
commit-msgは、コミット生成の直前に呼び出されますので、入力されたコミットメッセージが指定の書式に沿っているかのチェックに応用できます。
メッセージの書式が正しく無い場合は、コミットを生成できない、というようにすることが可能です。

post-commitは、コミットが正常に完了したら呼び出されますので、通知等に応用できます。
post-commitが実行された段階では、既にコミットは完了していますので、返り値が何であろうと中止はされません。

#!/bin/sh
# /.git/hooks/prepare-commit と /.git/hooks/commit-msg で同じ結果が得られる

echo $1  # 結果例: .git/COMMIT_EDITMSG
cat $1   # 結果例: any commit message
exit 0

prepare-commit-msg commit-msgが呼び出される際、第一引数には、コミットメッセージの書かれたファイルCOMMIT_EDITMSGへのパスが入力されます。

pre-commit post-commitでは、引数は入力されません。
git-loggit rev-parseコマンド等で、リポジトリの情報を取得して、何らかの動作をさせます。

commit-msgについて、実装例を作ってみました:

push 受け取り関係 (サーバサイド)

push に関する Git Hooks は、全部で 4つあります。
Git でのコミット生成の動作と合わせて説明すると、以下のように呼び出されます。

  1. git pushが実行される
  2. --- pre-receiveが実行される
  3. --- updateが、更新されたブランチ全てに実行される
  4. push が適用される
  5. --- post-receiveが実行される

Hook-Post.png

pre-receive updateにおいて、0 以外の返り値が発生した場合、その時点で push 受け取りが中止 (reject) されます。
post-receiveは、push が正常に適用されたら呼び出されますので、通知等に応用できます。

#!/bin/sh
# /hooks/pre-receive と /hooks/post-receive で同じ結果が得られる

read branch hash_old hash_new
echo $branch    # 結果例: refs/heads/master
echo $hash_old  # 結果例: aca07435522b6e5ed63481aada5733e421fabbb5
echo $hash_new  # 結果例: 90746b18c099aec161434e0c35238db219f8e76e
exit 0
#!/bin/sh
# /hooks/update

echo $1  # 結果例: refs/heads/master
echo $2  # 結果例: aca07435522b6e5ed63481aada5733e421fabbb5
echo $3  # 結果例: 90746b18c099aec161434e0c35238db219f8e76e
exit 0

updateでは、引数に値が入力されますが、pre-receivepost-receiveでは (なぜか) 標準入力 (read) で入力が来ます。
1つ目の値は、更新前時点で最新のコミットのハッシュが、2つ目の値は、更新後で最新のコミットのハッシュ、3つ目の値は操作が行われたブランチが入力されます。

pre-receiveupdateとでは、pre-receiveは 1度の push で 1度だけ実行される点、updateは、更新のかかったブランチ全てに実行される点が異なります。
例えば、branch1branch2を更新した後、git push --allとコマンドを実行した場合を考えます。
pre-receiveでは、その時点での操作先ブランチについての値が入力され、実行されます。
updateでは、refs/heads/branch1 refs/heads/branch2それぞれについて値が入力され、更新されたブランチの数実行されます。

GitHooks に使えそうなコマンド集

Git コマンドから UNIX 標準コマンドまで紹介。
(詳しい説明は省略。メモ程度にご覧ください。)

sed grep
テキストの置換や検索等、テキスト処理色々。
(一応書いておくと、) 加えてif thentest等、各種シェルスクリプトでよく使われるコマンドも必須です。

git log -n 1
コミット履歴のうち、最新のコミット 1つのみを表示。
1をその他の数字にすれば、その数字の数だけコミットを表示。

git log -n 1 <HASH>
コミット履歴のうち、<HASH>と一致するハッシュを持つコミットの情報を表示。

git status -s
git statusの結果をシンプル表示します。
Add や Modified 等を示す英数字とファイル名を各 1行ずつ表示。
行数をカウントすれば、変更のあったファイル数を得られます。

git rev-parse --short <HASH>
Git のコミットのハッシュ<HASH>を短縮したものを表示。

rev-parseコマンドは、他にも色々な情報の取得に使えます。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?