## Semantic Commit 大きな変更を意味のある最小単位に分割して、セマンティックなコミットメッセージと共に順次コミットします。外部ツールに依存せず、git 標準コマンドのみを使用します。 ### 使い方 ```bash /semantic-commit [オプション] ``` ### オプション - `--dry-run` : 実際のコミットは行わず、提案されるコミット分割のみを表示 - `--lang <言語>` : コミットメッセージの言語を強制指定 (en, ja) - `--max-commits <数>` : 最大コミット数を指定 (デフォルト: 10) ### 基本例 ```bash # 現在の変更を分析して、論理的な単位でコミット /semantic-commit # 分割案のみを確認 (実際のコミットなし) /semantic-commit --dry-run # 英語でコミットメッセージを生成 /semantic-commit --lang en # 日本語でコミットメッセージを生成 /semantic-commit --lang ja # 最大 5 個のコミットに分割 /semantic-commit --max-commits 5 ``` ### 動作フロー 1. **変更分析**: `git diff HEAD` で全変更を取得 2. **ファイル分類**: 変更されたファイルを論理的にグループ化 3. **コミット提案**: 各グループに対してセマンティックなコミットメッセージを生成 4. **順次実行**: ユーザー確認後、各グループを順次コミット ### 変更分割の核心機能 #### 「大きな変更」の検出 以下の条件で大きな変更として検出: 1. **変更ファイル数**: 5 ファイル以上の変更 2. **変更行数**: 100 行以上の変更 3. **複数機能**: 2 つ以上の機能領域にまたがる変更 4. **混在パターン**: feat + fix + docs が混在 ```bash # 変更規模の分析 CHANGED_FILES=$(git diff HEAD --name-only | wc -l) CHANGED_LINES=$(git diff HEAD --stat | tail -1 | grep -o '[0-9]\+ insertions\|[0-9]\+ deletions' | awk '{sum+=$1} END {print sum}') if [ $CHANGED_FILES -ge 5 ] || [ $CHANGED_LINES -ge 100 ]; then echo "大きな変更を検出: 分割を推奨" fi ``` #### 「意味のある最小単位」への分割戦略 ##### 1. 機能境界による分割 ```bash # ディレクトリ構造から機能単位を特定 git diff HEAD --name-only | cut -d'/' -f1-2 | sort | uniq # → src/auth, src/api, components/ui など ``` ##### 2. 変更種別による分離 ```bash # 新規ファイル vs 既存ファイル修正 git diff HEAD --name-status | grep '^A' # 新規ファイル git diff HEAD --name-status | grep '^M' # 修正ファイル git diff HEAD --name-status | grep '^D' # 削除ファイル ``` ##### 3. 依存関係の分析 ```bash # インポート関係の変更を検出 git diff HEAD | grep -E '^[+-].*import|^[+-].*require' | \ cut -d' ' -f2- | sort | uniq ``` #### ファイル単位の詳細分析 ```bash # 変更されたファイル一覧を取得 git diff HEAD --name-only # 各ファイルの変更内容を個別に分析 git diff HEAD -- # ファイルの変更タイプを判定 git diff HEAD --name-status | while read status file; do case $status in A) echo "$file: 新規作成" ;; M) echo "$file: 修正" ;; D) echo "$file: 削除" ;; R*) echo "$file: リネーム" ;; esac done ``` #### 論理的グループ化の基準 1. **機能単位**: 同一機能に関連するファイル - `src/auth/` 配下のファイル → 認証機能 - `components/` 配下のファイル → UI コンポーネント 2. **変更種別**: 同じ種類の変更 - テストファイルのみ → `test:` - ドキュメントのみ → `docs:` - 設定ファイルのみ → `chore:` 3. **依存関係**: 相互に関連するファイル - モデル + マイグレーション - コンポーネント + スタイル 4. **変更規模**: 適切なコミットサイズの維持 - 1 コミットあたり 10 ファイル以下 - 関連性の高いファイルをグループ化 ### 出力例 ```bash $ /semantic-commit 変更分析中... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 検出された変更: • src/auth/login.ts (修正) • src/auth/register.ts (新規) • src/auth/types.ts (修正) • tests/auth.test.ts (新規) • docs/authentication.md (新規) 提案されるコミット分割: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ コミット 1/3 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ メッセージ: feat: implement user registration and login system 含まれるファイル: • src/auth/login.ts • src/auth/register.ts • src/auth/types.ts ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ コミット 2/3 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ メッセージ: test: add comprehensive tests for authentication system 含まれるファイル: • tests/auth.test.ts ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ コミット 3/3 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ メッセージ: docs: add authentication system documentation 含まれるファイル: • docs/authentication.md この分割案でコミットを実行しますか? (y/n/edit): ``` ### 実行時の選択肢 - `y` : 提案されたコミット分割で実行 - `n` : キャンセル - `edit` : コミットメッセージを個別に編集 - `merge <番号 1> <番号 2>` : 指定したコミットをマージ - `split <番号>` : 指定したコミットをさらに分割 ### Dry Run モード ```bash $ /semantic-commit --dry-run 変更分析中... (DRY RUN) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [コミット分割提案の表示] ℹ️ DRY RUN モード: 実際のコミットは実行されません 💡 実行する場合は --dry-run オプションを除いて再実行してください ``` ### スマート分析機能 #### 1. プロジェクト構造の理解 - `package.json`, `Cargo.toml`, `pom.xml` などからプロジェクト種別を判定 - フォルダ構造から機能単位を推測 #### 2. 変更パターンの認識 ```bash # バグ修正パターンの検出 - "fix", "bug", "error" などのキーワード - 例外処理の追加 - 条件分岐の修正 # 新機能パターンの検出 - 新ファイル作成 - 新メソッド追加 - API エンドポイント追加 ``` #### 3. 依存関係の分析 - インポート文の変更 - 型定義の追加/修正 - 設定ファイルとの関連性 ### 技術的実装 #### Git 標準コマンドによる順次コミット実装 ##### 1. 前処理: 現在の状態を保存 ```bash # 未ステージの変更がある場合は一旦リセット git reset HEAD git status --porcelain > /tmp/original_state.txt # 作業ブランチの確認 CURRENT_BRANCH=$(git branch --show-current) echo "作業中のブランチ: $CURRENT_BRANCH" ``` ##### 2. グループ別の順次コミット実行 ```bash # 分割計画の読み込み while IFS= read -r commit_plan; do group_num=$(echo "$commit_plan" | cut -d':' -f1) files=$(echo "$commit_plan" | cut -d':' -f2- | tr ' ' '\n') echo "=== コミット $group_num の実行 ===" # 該当ファイルのみをステージング echo "$files" | while read file; do if [ -f "$file" ]; then git add "$file" echo "ステージング: $file" fi done # ステージング状態の確認 staged_files=$(git diff --staged --name-only) if [ -z "$staged_files" ]; then echo "警告: ステージングされたファイルがありません" continue fi # コミットメッセージの生成 (LLM による分析) commit_msg=$(generate_commit_message_for_staged_files) # ユーザー確認 echo "提案コミットメッセージ: $commit_msg" echo "ステージングされたファイル:" echo "$staged_files" read -p "このコミットを実行しますか? (y/n): " confirm if [ "$confirm" = "y" ]; then # コミット実行 git commit -m "$commit_msg" echo "✅ コミット $group_num 完了" else # ステージングを取り消し git reset HEAD echo "❌ コミット $group_num をスキップ" fi done < /tmp/commit_plan.txt ``` ##### 3. エラーハンドリングとロールバック ```bash # プリコミットフック失敗時の処理 commit_with_retry() { local commit_msg="$1" local max_retries=2 local retry_count=0 while [ $retry_count -lt $max_retries ]; do if git commit -m "$commit_msg"; then echo "✅ コミット成功" return 0 else echo "❌ コミット失敗 (試行 $((retry_count + 1))/$max_retries)" # プリコミットフックによる自動修正を取り込み if git diff --staged --quiet; then echo "プリコミットフックにより変更が自動修正されました" git add -u fi retry_count=$((retry_count + 1)) fi done echo "❌ コミットに失敗しました。手動で確認してください。" return 1 } # 中断からの復旧 resume_from_failure() { echo "中断されたコミット処理を検出しました" echo "現在のステージング状態:" git status --porcelain read -p "処理を続行しますか? (y/n): " resume if [ "$resume" = "y" ]; then # 最後のコミット位置から再開 last_commit=$(git log --oneline -1 --pretty=format:"%s") echo "最後のコミット: $last_commit" else # 完全リセット git reset HEAD echo "処理をリセットしました" fi } ``` ##### 4. 完了後の検証 ```bash # 全変更がコミットされたかの確認 remaining_changes=$(git status --porcelain | wc -l) if [ $remaining_changes -eq 0 ]; then echo "✅ すべての変更がコミットされました" else echo "⚠️ 未コミットの変更が残っています:" git status --short fi # コミット履歴の表示 echo "作成されたコミット:" git log --oneline -n 10 --graph ``` ##### 5. 自動プッシュの抑制 ```bash # 注意: 自動プッシュは行わない echo "📝 注意: 自動プッシュは実行されません" echo "必要に応じて以下のコマンドでプッシュしてください:" echo " git push origin $CURRENT_BRANCH" ``` #### 分割アルゴリズムの詳細 ##### ステップ 1: 初期分析 ```bash # 全変更ファイルの取得と分類 git diff HEAD --name-status | while read status file; do echo "$status:$file" done > /tmp/changes.txt # 機能ディレクトリ別の変更統計 git diff HEAD --name-only | cut -d'/' -f1-2 | sort | uniq -c ``` ##### ステップ 2: 機能境界による初期グループ化 ```bash # ディレクトリベースのグループ化 GROUPS=$(git diff HEAD --name-only | cut -d'/' -f1-2 | sort | uniq) for group in $GROUPS; do echo "=== グループ: $group ===" git diff HEAD --name-only | grep "^$group" | head -10 done ``` ##### ステップ 3: 変更内容の類似性分析 ```bash # 各ファイルの変更タイプを分析 git diff HEAD --name-only | while read file; do # 新規関数/クラス追加の検出 NEW_FUNCTIONS=$(git diff HEAD -- "$file" | grep -c '^+.*function\|^+.*class\|^+.*def ') # バグ修正パターンの検出 BUG_FIXES=$(git diff HEAD -- "$file" | grep -c '^+.*fix\|^+.*bug\|^-.*error') # テストファイルかの判定 if [[ "$file" =~ test|spec ]]; then echo "$file: TEST" elif [ $NEW_FUNCTIONS -gt 0 ]; then echo "$file: FEAT" elif [ $BUG_FIXES -gt 0 ]; then echo "$file: FIX" else echo "$file: REFACTOR" fi done ``` ##### ステップ 4: 依存関係による調整 ```bash # インポート関係の分析 git diff HEAD | grep -E '^[+-].*import|^[+-].*from.*import' | \ while read line; do echo "$line" | sed 's/^[+-]//' | awk '{print $2}' done | sort | uniq > /tmp/imports.txt # 関連ファイルのグループ化 git diff HEAD --name-only | while read file; do basename=$(basename "$file" .js .ts .py) related=$(git diff HEAD --name-only | grep "$basename" | grep -v "^$file$") if [ -n "$related" ]; then echo "関連ファイル群: $file <-> $related" fi done ``` ##### ステップ 5: コミットサイズの最適化 ```bash # グループサイズの調整 MAX_FILES_PER_COMMIT=8 current_group=1 file_count=0 git diff HEAD --name-only | while read file; do if [ $file_count -ge $MAX_FILES_PER_COMMIT ]; then current_group=$((current_group + 1)) file_count=0 fi echo "コミット $current_group: $file" file_count=$((file_count + 1)) done ``` ##### ステップ 6: 最終グループ決定 ```bash # 分割結果の検証 for group in $(seq 1 $current_group); do files=$(grep "コミット $group:" /tmp/commit_plan.txt | cut -d':' -f2-) lines=$(echo "$files" | xargs git diff HEAD -- | wc -l) echo "コミット $group: $(echo "$files" | wc -w) ファイル, $lines 行変更" done ``` ### Conventional Commits 準拠 #### 基本形式 ```text [optional scope]: [optional body] [optional footer(s)] ``` #### 標準タイプ **必須タイプ**: - `feat`: 新機能 (ユーザーに見える機能追加) - `fix`: バグ修正 **任意タイプ**: - `build`: ビルドシステムや外部依存関係の変更 - `chore`: その他の変更 (リリースに影響しない) - `ci`: CI 設定ファイルやスクリプトの変更 - `docs`: ドキュメントのみの変更 - `style`: コードの意味に影響しない変更 (空白、フォーマット、セミコロンなど) - `refactor`: バグ修正や機能追加を伴わないコード変更 - `perf`: パフォーマンス改善 - `test`: テストの追加や修正 #### スコープ (任意) 変更の影響範囲を示す: ```text feat(api): add user authentication endpoint fix(ui): resolve button alignment issue docs(readme): update installation instructions ``` #### Breaking Change API の破壊的変更がある場合: ```text feat!: change user API response format BREAKING CHANGE: user response now includes additional metadata ``` または ```text feat(api)!: change authentication flow ``` #### プロジェクト規約の自動検出 **重要**: プロジェクト独自の規約が存在する場合は、それを優先します。 ##### 1. CommitLint 設定の確認 以下のファイルから設定を自動検出: - `commitlint.config.js` - `commitlint.config.mjs` - `commitlint.config.cjs` - `commitlint.config.ts` - `.commitlintrc.js` - `.commitlintrc.json` - `.commitlintrc.yml` - `.commitlintrc.yaml` - `package.json` の `commitlint` セクション ```bash # 設定ファイル例の確認 cat commitlint.config.mjs cat .commitlintrc.json grep -A 10 '"commitlint"' package.json ``` ##### 2. カスタムタイプの検出 プロジェクト独自のタイプ例: ```javascript // commitlint.config.mjs export default { extends: ["@commitlint/config-conventional"], rules: { "type-enum": [ 2, "always", [ "feat", "fix", "docs", "style", "refactor", "test", "chore", "wip", // 作業中 "hotfix", // 緊急修正 "release", // リリース "deps", // 依存関係更新 "config", // 設定変更 ], ], }, }; ``` ##### 3. 言語設定の検出 ```javascript // プロジェクトが日本語メッセージを使用する場合 export default { rules: { "subject-case": [0], // 日本語対応のため無効化 "subject-max-length": [2, "always", 72], // 日本語は文字数制限を調整 }, }; ``` #### 自動分析の流れ 1. **設定ファイル検索** ```bash find . -name "commitlint.config.*" -o -name ".commitlintrc.*" | head -1 ``` 2. **既存コミット分析** ```bash git log --oneline -50 --pretty=format:"%s" ``` 3. **使用タイプ統計** ```bash git log --oneline -100 --pretty=format:"%s" | \ grep -oE '^[a-z]+(\([^)]+\))?' | \ sort | uniq -c | sort -nr ``` #### プロジェクト規約の例 ##### Angular スタイル ```text feat(scope): add new feature fix(scope): fix bug docs(scope): update documentation ``` ##### Gitmoji 併用スタイル ```text ✨ feat: add user registration 🐛 fix: resolve login issue 📚 docs: update API docs ``` ##### 日本語プロジェクト ```text feat: ユーザー登録機能を追加 fix: ログイン処理のバグを修正 docs: API ドキュメントを更新 ``` ### 言語判定 このコマンドで完結する言語判定ロジック: 1. **CommitLint 設定**から言語設定を確認 ```bash # subject-case ルールが無効化されている場合は日本語と判定 grep -E '"subject-case".*\[0\]|subject-case.*0' commitlint.config.* ``` 2. **git log 分析**による自動判定 ```bash # 最近 20 コミットの言語を分析 git log --oneline -20 --pretty=format:"%s" | \ grep -E '^[あ-ん]|[ア-ン]|[一-龯]' | wc -l # 50% 以上が日本語なら日本語モード ``` 3. **プロジェクトファイル**の言語設定 ```bash # README.md の言語確認 head -10 README.md | grep -E '^[あ-ん]|[ア-ン]|[一-龯]' | wc -l # package.json の description 確認 grep -E '"description".*[あ-ん]|[ア-ン]|[一-龯]' package.json ``` 4. **変更ファイル内**のコメント・文字列分析 ```bash # 変更されたファイルのコメント言語を確認 git diff HEAD | grep -E '^[+-].*//.*[あ-ん]|[ア-ン]|[一-龯]' | wc -l ``` #### 判定アルゴリズム ```bash # 言語判定スコア計算 JAPANESE_SCORE=0 # 1. CommitLint 設定 (+3 点) if grep -q '"subject-case".*\[0\]' commitlint.config.* 2>/dev/null; then JAPANESE_SCORE=$((JAPANESE_SCORE + 3)) fi # 2. git log 分析 (最大+2 点) JAPANESE_COMMITS=$(git log --oneline -20 --pretty=format:"%s" | \ grep -cE '[あ-ん]|[ア-ン]|[一-龯]' 2>/dev/null || echo 0) if [ $JAPANESE_COMMITS -gt 10 ]; then JAPANESE_SCORE=$((JAPANESE_SCORE + 2)) elif [ $JAPANESE_COMMITS -gt 5 ]; then JAPANESE_SCORE=$((JAPANESE_SCORE + 1)) fi # 3. README.md 確認 (+1 点) if head -5 README.md 2>/dev/null | grep -qE '[あ-ん]|[ア-ン]|[一-龯]'; then JAPANESE_SCORE=$((JAPANESE_SCORE + 1)) fi # 4. 変更ファイル内容確認 (+1 点) if git diff HEAD 2>/dev/null | grep -qE '^[+-].*[あ-ん]|[ア-ン]|[一-龯]'; then JAPANESE_SCORE=$((JAPANESE_SCORE + 1)) fi # 判定: 3 点以上で日本語モード if [ $JAPANESE_SCORE -ge 3 ]; then LANGUAGE="ja" else LANGUAGE="en" fi ``` ### 設定ファイル自動読み込み #### 実行時の動作 コマンド実行時に以下の順序で設定を確認: 1. **CommitLint 設定ファイルの検索** ```bash # 以下の順序で検索し、最初に見つかったファイルを使用 commitlint.config.mjs commitlint.config.js commitlint.config.cjs commitlint.config.ts .commitlintrc.js .commitlintrc.json .commitlintrc.yml .commitlintrc.yaml package.json (commitlint セクション) ``` 2. **設定内容の解析** - 使用可能なタイプの一覧を抽出 - スコープの制限があるかを確認 - メッセージ長制限の取得 - 言語設定の確認 3. **既存コミット履歴の分析** ```bash # 最近のコミットから使用パターンを学習 git log --oneline -100 --pretty=format:"%s" | \ head -20 ``` #### 設定例の分析 **標準的な commitlint.config.mjs**: ```javascript export default { extends: ["@commitlint/config-conventional"], rules: { "type-enum": [ 2, "always", ["feat", "fix", "docs", "style", "refactor", "perf", "test", "chore"], ], "scope-enum": [2, "always", ["api", "ui", "core", "auth", "db"]], }, }; ``` **日本語対応の設定**: ```javascript export default { extends: ["@commitlint/config-conventional"], rules: { "subject-case": [0], // 日本語のため無効化 "subject-max-length": [2, "always", 72], "type-enum": [ 2, "always", ["feat", "fix", "docs", "style", "refactor", "test", "chore"], ], }, }; ``` **カスタムタイプを含む設定**: ```javascript export default { extends: ["@commitlint/config-conventional"], rules: { "type-enum": [ 2, "always", [ "feat", "fix", "docs", "style", "refactor", "test", "chore", "wip", // Work in Progress "hotfix", // 緊急修正 "release", // リリース準備 "deps", // 依存関係更新 "config", // 設定変更 ], ], }, }; ``` #### フォールバック動作 設定ファイルが見つからない場合: 1. **git log 分析**による自動推測 ```bash # 最近 100 コミットからタイプを抽出 git log --oneline -100 --pretty=format:"%s" | \ grep -oE '^[a-z]+(\([^)]+\))?' | \ sort | uniq -c | sort -nr ``` 2. **Conventional Commits 標準**をデフォルト使用 ``` feat, fix, docs, style, refactor, perf, test, chore, build, ci ``` 3. **言語判定** - 日本語コミットが 50% 以上 → 日本語モード - その他 → 英語モード ### 前提条件 - Git リポジトリ内で実行 - 未コミットの変更が存在すること - ステージングされた変更は一旦リセットされます ### 注意事項 - **自動プッシュなし**: コミット後の `git push` は手動実行 - **ブランチ作成なし**: 現在のブランチでコミット - **バックアップ推奨**: 重要な変更前には `git stash` でバックアップ ### プロジェクト規約の優先度 コミットメッセージ生成時の優先度: 1. **CommitLint 設定** (最優先) - `commitlint.config.*` ファイルの設定 - カスタムタイプやスコープの制限 - メッセージ長やケースの制限 2. **既存コミット履歴** (第 2 優先) - 実際に使用されているタイプの統計 - メッセージの言語 (日本語/英語) - スコープの使用パターン 3. **プロジェクト種別** (第 3 優先) - `package.json` → Node.js プロジェクト - `Cargo.toml` → Rust プロジェクト - `pom.xml` → Java プロジェクト 4. **Conventional Commits 標準** (フォールバック) - 設定が見つからない場合の標準動作 #### 規約検出の実例 **Monorepo での scope 自動検出**: ```bash # packages/ フォルダから scope を推測 ls packages/ | head -10 # → api, ui, core, auth などを scope として提案 ``` **フレームワーク固有の規約**: ```javascript // Angular プロジェクトの場合 { 'scope-enum': [2, 'always', [ 'animations', 'common', 'core', 'forms', 'http', 'platform-browser', 'platform-server', 'router', 'service-worker', 'upgrade' ]] } // React プロジェクトの場合 { 'scope-enum': [2, 'always', [ 'components', 'hooks', 'utils', 'types', 'styles', 'api' ]] } ``` **企業・チーム固有の規約**: ```javascript // 日本の企業でよく見られるパターン { 'type-enum': [2, 'always', [ 'feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore', 'wip', // 作業中 (プルリクエスト用) 'hotfix', // 緊急修正 'release' // リリース準備 ]], 'subject-case': [0], // 日本語対応 'subject-max-length': [2, 'always', 72] // 日本語は長めに設定 } ``` ### ベストプラクティス 1. **プロジェクト規約の尊重**: 既存の設定やパターンに従う 2. **小さな変更単位**: 1 つのコミットは 1 つの論理的変更 3. **明確なメッセージ**: 何を変更したかが明確 4. **関連性の重視**: 機能的に関連するファイルをグループ化 5. **テストの分離**: テストファイルは別コミットに 6. **設定ファイルの活用**: CommitLint を導入してチーム全体で規約を統一 ### 実際の分割例 (Before/After) #### 例 1: 大規模な認証システム追加 **Before(1 つの巨大なコミット):** ```bash # 変更されたファイル (15 ファイル、850 行変更) src/auth/login.js # 新規作成 src/auth/register.js # 新規作成 src/auth/password.js # 新規作成 src/auth/types.js # 新規作成 src/api/auth-routes.js # 新規作成 src/middleware/auth.js # 新規作成 src/database/migrations/001_users.sql # 新規作成 src/database/models/user.js # 新規作成 tests/auth/login.test.js # 新規作成 tests/auth/register.test.js # 新規作成 tests/api/auth-routes.test.js # 新規作成 docs/authentication.md # 新規作成 package.json # 依存関係追加 README.md # 使用方法追加 .env.example # 環境変数例追加 # 従来の問題のあるコミット feat: implement complete user authentication system with login, registration, password reset, API routes, database models, tests and documentation ``` **After(意味のある 5 つのコミットに分割):** ```bash # コミット 1: データベース基盤 feat(db): add user model and authentication schema 含まれるファイル: - src/database/migrations/001_users.sql - src/database/models/user.js - src/auth/types.js 理由: データベース構造は他の機能の基盤となるため最初にコミット # コミット 2: 認証ロジック feat(auth): implement core authentication functionality 含まれるファイル: - src/auth/login.js - src/auth/register.js - src/auth/password.js - src/middleware/auth.js 理由: 認証の核となるビジネスロジックを一括でコミット # コミット 3: API エンドポイント feat(api): add authentication API routes 含まれるファイル: - src/api/auth-routes.js 理由: API レイヤーは認証ロジックに依存するため後でコミット # コミット 4: 包括的なテスト test(auth): add comprehensive authentication tests 含まれるファイル: - tests/auth/login.test.js - tests/auth/register.test.js - tests/api/auth-routes.test.js 理由: 実装完了後にテストを一括追加 # コミット 5: 設定とドキュメント docs(auth): add authentication documentation and configuration 含まれるファイル: - docs/authentication.md - package.json - README.md - .env.example 理由: ドキュメントと設定は最後にまとめてコミット ``` #### 例 2: バグ修正とリファクタリングの混在 **Before(混在した問題のあるコミット):** ```bash # 変更されたファイル (8 ファイル、320 行変更) src/user/service.js # バグ修正 + リファクタリング src/user/validator.js # 新規作成 (リファクタリング) src/auth/middleware.js # バグ修正 src/api/user-routes.js # バグ修正 + エラーハンドリング改善 tests/user.test.js # テスト追加 tests/auth.test.js # バグ修正テスト追加 docs/user-api.md # ドキュメント更新 package.json # 依存関係更新 # 問題のあるコミット fix: resolve user validation bugs and refactor validation logic with improved error handling ``` **After(種別別に 3 つのコミットに分割):** ```bash # コミット 1: 緊急バグ修正 fix: resolve user validation and authentication bugs 含まれるファイル: - src/user/service.js(バグ修正部分のみ) - src/auth/middleware.js - tests/auth.test.js(バグ修正テストのみ) 理由: 本番環境に影響するバグは最優先で修正 # コミット 2: バリデーションロジックのリファクタリング refactor: extract and improve user validation logic 含まれるファイル: - src/user/service.js(リファクタリング部分) - src/user/validator.js - src/api/user-routes.js - tests/user.test.js 理由: 構造改善は機能単位でまとめてコミット # コミット 3: ドキュメントと依存関係更新 chore: update documentation and dependencies 含まれるファイル: - docs/user-api.md - package.json 理由: 開発環境の整備は最後にまとめてコミット ``` #### 例 3: 複数機能の同時開発 **Before(機能横断の巨大コミット):** ```bash # 変更されたファイル (12 ファイル、600 行変更) src/user/profile.js # 新機能 A src/user/avatar.js # 新機能 A src/notification/email.js # 新機能 B src/notification/sms.js # 新機能 B src/api/profile-routes.js # 新機能 A 用 API src/api/notification-routes.js # 新機能 B 用 API src/dashboard/widgets.js # 新機能 C src/dashboard/charts.js # 新機能 C tests/profile.test.js # 新機能 A 用テスト tests/notification.test.js # 新機能 B 用テスト tests/dashboard.test.js # 新機能 C 用テスト package.json # 全機能の依存関係 # 問題のあるコミット feat: add user profile management, notification system and dashboard widgets ``` **After(機能別に 4 つのコミットに分割):** ```bash # コミット 1: ユーザープロフィール機能 feat(profile): add user profile management 含まれるファイル: - src/user/profile.js - src/user/avatar.js - src/api/profile-routes.js - tests/profile.test.js 理由: プロフィール機能は独立した機能単位 # コミット 2: 通知システム feat(notification): implement email and SMS notifications 含まれるファイル: - src/notification/email.js - src/notification/sms.js - src/api/notification-routes.js - tests/notification.test.js 理由: 通知機能は独立した機能単位 # コミット 3: ダッシュボードウィジェット feat(dashboard): add interactive widgets and charts 含まれるファイル: - src/dashboard/widgets.js - src/dashboard/charts.js - tests/dashboard.test.js 理由: ダッシュボード機能は独立した機能単位 # コミット 4: 依存関係とインフラ更新 chore: update dependencies for new features 含まれるファイル: - package.json 理由: 共通の依存関係更新は最後にまとめて ``` ### 分割効果の比較 | 項目 | Before(巨大コミット) | After(適切な分割) | | -------------- | ----------------------------- | --------------------------------------- | | **レビュー性** | ❌ 非常に困難 | ✅ 各コミットが小さくレビュー可能 | | **バグ追跡** | ❌ 問題箇所の特定が困難 | ✅ 問題のあるコミットを即座に特定 | | **リバート** | ❌ 全体をリバートする必要 | ✅ 問題部分のみをピンポイントでリバート | | **並行開発** | ❌ コンフリクトが発生しやすい | ✅ 機能別でマージが容易 | | **デプロイ** | ❌ 全機能を一括デプロイ | ✅ 段階的なデプロイが可能 | ### トラブルシューティング #### コミット失敗時 - プリコミットフックの確認 - 依存関係の解決 - 個別ファイルでの再試行 #### 分割が適切でない場合 - `--max-commits` オプションで調整 - 手動での `edit` モード使用 - より細かい単位での再実行