メインコンテンツへスキップ
レッスン 11 / 15推定時間: 25

フックとカスタマイズ

Gitフックを使って開発フローを自動化し、チームの生産性を向上させる方法を学びましょう

このレッスンの学習目標

  • Gitフックの仕組みと種類を理解する
  • よく使われるフックを実装できる
  • チームでフックを共有する方法を学ぶ

Gitフックとは?

Gitフック(Git Hooks)は、Gitの特定のイベントが発生した際に自動的に実行されるスクリプトです。コミット前のコード検証、プッシュ前のテスト実行など、様々な自動化が可能です。

なぜフックが必要?

🤖 品質の自動化

  • 「コーディング規約違反のコードがコミットされる」
  • 「テストを忘れてプッシュしてしまう」
  • 「コミットメッセージが統一されていない」

⏱️ 時間の節約

  • 「毎回同じチェックを手動で実行している」
  • 「レビューで同じ指摘を繰り返している」
  • 「ビルドエラーでCIが失敗する」

フックの種類

クライアントサイドフック

ローカルリポジトリで実行されるフックです。

1. pre-commit

コミット前に実行。コード品質チェックに最適。

#!/bin/sh
# .git/hooks/pre-commit

# ESLintでコードチェック
npm run lint
if [ $? -ne 0 ]; then
    echo "❌ Lintエラーが見つかりました。修正してください。"
    exit 1
fi

# フォーマットチェック
npm run format:check
if [ $? -ne 0 ]; then
    echo "❌ フォーマットエラー。'npm run format'を実行してください。"
    exit 1
fi

echo "✅ Pre-commitチェック完了"

2. prepare-commit-msg

コミットメッセージエディタが開く前に実行。

#!/bin/sh
# .git/hooks/prepare-commit-msg

# ブランチ名からIssue番号を抽出してメッセージに追加
BRANCH=$(git branch --show-current)
ISSUE=$(echo $BRANCH | grep -o '[0-9]\+')

if [ -n "$ISSUE" ]; then
    sed -i.bak "1s/^/[#$ISSUE] /" "$1"
fi

3. commit-msg

コミットメッセージの検証。

#!/bin/sh
# .git/hooks/commit-msg

# コミットメッセージの形式をチェック
commit_regex='^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .{1,50}'

if ! grep -qE "$commit_regex" "$1"; then
    echo "❌ コミットメッセージが規約に従っていません!"
    echo "📝 正しい形式: <type>(<scope>): <subject>"
    echo "例: feat(auth): ログイン機能を追加"
    exit 1
fi

4. pre-push

プッシュ前に実行。最終チェックに使用。

#!/bin/sh
# .git/hooks/pre-push

# テストを実行
echo "🧪 テストを実行中..."
npm test
if [ $? -ne 0 ]; then
    echo "❌ テストが失敗しました。修正してください。"
    exit 1
fi

echo "✅ すべてのテストが成功しました"

サーバーサイドフック

リモートリポジトリで実行されるフックです。

1. pre-receive

プッシュを受信する前に実行。

#!/bin/sh
# hooks/pre-receive

while read oldrev newrev refname; do
    # 大きなファイルをチェック
    files=$(git diff --name-only $oldrev $newrev)
    for file in $files; do
        size=$(git cat-file -s $newrev:$file 2>/dev/null)
        if [ $size -gt 10485760 ]; then  # 10MB
            echo "❌ エラー: $file が10MBを超えています"
            exit 1
        fi
    done
done

フックの実装

基本的なフックの作成

# フックスクリプトを作成
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/sh
echo "🔍 Pre-commitフックを実行中..."

# ステージングされたファイルを取得
files=$(git diff --cached --name-only --diff-filter=ACM | grep '\.js$')

if [ -z "$files" ]; then
    exit 0
fi

# 各ファイルをチェック
for file in $files; do
    # debuggerが残っていないかチェック
    if grep -n "debugger" "$file"; then
        echo "❌ エラー: $file にdebuggerが残っています"
        exit 1
    fi
    
    # console.logが残っていないかチェック
    if grep -n "console\.log" "$file"; then
        echo "⚠️  警告: $file にconsole.logが残っています"
    fi
done

echo "✅ Pre-commitチェック完了"
EOF

# 実行権限を付与
chmod +x .git/hooks/pre-commit

高度なフック例

セキュリティチェック

#!/bin/sh
# .git/hooks/pre-commit

# APIキーやパスワードのパターンをチェック
patterns=(
    "api[_-]?key.*=.*['\"][^'\"]{20,}['\"]"
    "password.*=.*['\"][^'\"]+['\"]"
    "secret.*=.*['\"][^'\"]+['\"]"
    "AWS[_-]?ACCESS[_-]?KEY"
    "private[_-]?key"
)

files=$(git diff --cached --name-only)

for file in $files; do
    for pattern in "${patterns[@]}"; do
        if grep -iE "$pattern" "$file"; then
            echo "❌ セキュリティ警告: $file に機密情報が含まれている可能性があります"
            echo "パターン: $pattern"
            exit 1
        fi
    done
done

フックの共有

Huksyを使用した共有

// package.json
{
  "devDependencies": {
    "husky": "^8.0.0"
  },
  "scripts": {
    "prepare": "husky install"
  }
}
# Huskyのセットアップ
npm install husky --save-dev
npx husky install

# pre-commitフックを追加
npx husky add .husky/pre-commit "npm run lint"
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'

カスタムフックディレクトリ

# プロジェクトにフックを含める
mkdir .githooks

# pre-commitフックを作成
cat > .githooks/pre-commit << 'EOF'
#!/bin/sh
npm run lint && npm run test:unit
EOF

chmod +x .githooks/pre-commit

# Gitの設定でフックディレクトリを指定
git config core.hooksPath .githooks

実践演習

CommandAcademy Terminal
Welcome to CommandAcademy Terminal!
Type "help" to see available commands.
user@cmdac:~$

ファイルツリー

/
etc
hosts35B
passwd76B
home
user
tmp
usr
bin
share
var
log

フックのベストプラクティス

1. パフォーマンスへの配慮

# ❌ 悪い例:すべてのファイルをチェック
find . -name "*.js" | xargs eslint

# ✅ 良い例:変更されたファイルのみチェック
git diff --cached --name-only --diff-filter=ACM | grep '\.js$' | xargs eslint

2. エラーメッセージの改善

# ❌ 悪い例
echo "Error"
exit 1

# ✅ 良い例
echo "❌ ESLintエラー: 以下のファイルを修正してください:"
echo "$failed_files"
echo ""
echo "修正方法: npm run lint:fix"
echo "詳細確認: npm run lint"
exit 1

3. スキップオプションの提供

# 緊急時のスキップを許可
if [ "$SKIP_HOOKS" = "1" ]; then
    echo "⚠️  フックをスキップしました"
    exit 0
fi

# 使用方法: SKIP_HOOKS=1 git commit -m "緊急修正"

トラブルシューティング

フックが実行されない

# 実行権限を確認
ls -la .git/hooks/

# 実行権限を付与
chmod +x .git/hooks/*

# フックパスを確認
git config core.hooksPath

フックのデバッグ

#!/bin/sh
# デバッグモードを有効化
set -x  # コマンドを表示
set -e  # エラーで停止

# ログファイルに出力
exec > >(tee -a /tmp/git-hook.log)
exec 2>&1

echo "[$(date)] Hook started: $0"

まとめ

Gitフックは、チームの開発品質を自動的に保つ強力なツールです。適切に設定することで:

  1. 品質向上: 問題を早期に発見
  2. 時間節約: 手動チェックを自動化
  3. 一貫性: チーム全体で同じルールを適用

ただし、過度に厳しいフックは開発速度を落とす可能性があるため、バランスが重要です。

次のレッスンでは、CI/CDとの連携について学ぶ「GitHub Actions/GitLab CI」について学びます。

さらに学習を続けるには

素晴らしい学習ペースです!次のレッスンに進むには、無料会員登録をお願いします。無料会員では各コース3レッスンまで学習できます。

無料で続きを学ぶ

各コース3レッスンまで学習可能

学習進捗の自動保存

コース修了証明書の発行