From cook-en
Splits uncommitted changes into logical, semantic commits with meaningful messages using git commands.
How this skill is triggered — by the user, by Claude, or both
Slash command
/cook-en:semantic-commitThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Breaks big changes into small, meaningful commits with proper messages. Uses only standard git commands.
Breaks big changes into small, meaningful commits with proper messages. Uses only standard git commands.
/semantic-commit [options]
--dry-run: Show proposed commit splits without actually committing--lang <language>: Force language for commit messages (en)--max-commits <number>: Specify maximum number of commits (default: 10)# Analyze current changes and commit in logical units
/semantic-commit
# Check split proposal only (no actual commit)
/semantic-commit --dry-run
# Generate commit messages in English
/semantic-commit --lang en
# Split into maximum 5 commits
/semantic-commit --max-commits 5
git diff HEADWe split when we see:
# Analyze change scale
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 "Large change detected: splitting recommended"
fi
# Identify functional units from directory structure
git diff HEAD --name-only | cut -d'/' -f1-2 | sort | uniq
# → src/auth, src/api, components/ui, etc.
# New files vs existing file modifications
git diff HEAD --name-status | grep '^A' # New files
git diff HEAD --name-status | grep '^M' # Modified files
git diff HEAD --name-status | grep '^D' # Deleted files
# Detect import relationship changes
git diff HEAD | grep -E '^[+-].*import|^[+-].*require' | \
cut -d' ' -f2- | sort | uniq
# Get list of changed files
git diff HEAD --name-only
# Analyze each file's changes individually
git diff HEAD -- <file>
# Determine change type for files
git diff HEAD --name-status | while read status file; do
case $status in
A) echo "$file: New creation" ;;
M) echo "$file: Modification" ;;
D) echo "$file: Deletion" ;;
R*) echo "$file: Renamed" ;;
esac
done
By Feature: Keep related functions together
src/auth/ files → Authenticationcomponents/ files → UI componentsBy Type: Same kind of changes
test:docs:chore:By Dependencies: Files that need each other
By Size: Keep commits manageable
$ /semantic-commit
Analyzing changes...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Detected changes:
• src/auth/login.ts (modified)
• src/auth/register.ts (new)
• src/auth/types.ts (modified)
• tests/auth.test.ts (new)
• docs/authentication.md (new)
Proposed commit splits:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Commit 1/3
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Message: feat: implement user registration and login system
Included files:
• src/auth/login.ts
• src/auth/register.ts
• src/auth/types.ts
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Commit 2/3
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Message: test: add comprehensive tests for authentication system
Included files:
• tests/auth.test.ts
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Commit 3/3
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Message: docs: add authentication system documentation
Included files:
• docs/authentication.md
Execute commit with this split plan? (y/n/edit):
y: Go with the proposed splitn: Cancel everythingedit: Change commit messagesmerge <number1> <number2>: Combine commitssplit <number>: Break up a commit more$ /semantic-commit --dry-run
Analyzing changes... (DRY RUN)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[Commit split proposal display]
ℹ️ DRY RUN mode: No actual commits will be executed
💡 To execute, run again without --dry-run option
# Detect bug fix patterns
- Keywords like "fix", "bug", "error"
- Addition of exception handling
- Condition branch fixes
# Detect new feature patterns
- New file creation
- New method additions
- API endpoint additions
# Reset unstaged changes if any
git reset HEAD
git status --porcelain > /tmp/original_state.txt
# Check working branch
CURRENT_BRANCH=$(git branch --show-current)
echo "Working branch: $CURRENT_BRANCH"
# Read split plan
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 "=== Executing commit $group_num ==="
# Stage only relevant files
echo "$files" | while read file; do
if [ -f "$file" ]; then
git add "$file"
echo "Staged: $file"
fi
done
# Check staging status
staged_files=$(git diff --staged --name-only)
if [ -z "$staged_files" ]; then
echo "Warning: No files staged"
continue
fi
# Generate commit message (LLM analysis)
commit_msg=$(generate_commit_message_for_staged_files)
# User confirmation
echo "Proposed commit message: $commit_msg"
echo "Staged files:"
echo "$staged_files"
read -p "Execute this commit? (y/n): " confirm
if [ "$confirm" = "y" ]; then
# Execute commit
git commit -m "$commit_msg"
echo "✅ Commit $group_num completed"
else
# Cancel staging
git reset HEAD
echo "❌ Skipped commit $group_num"
fi
done < /tmp/commit_plan.txt
# Handle pre-commit hook failures
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 "✅ Commit successful"
return 0
else
echo "❌ Commit failed (attempt $((retry_count + 1))/$max_retries)"
# Incorporate automatic fixes from pre-commit hooks
if git diff --staged --quiet; then
echo "Changes automatically fixed by pre-commit hook"
git add -u
fi
retry_count=$((retry_count + 1))
fi
done
echo "❌ Failed to commit. Please check manually."
return 1
}
# Recover from interruptions
resume_from_failure() {
echo "Detected interrupted commit process"
echo "Current staging status:"
git status --porcelain
read -p "Continue processing? (y/n): " resume
if [ "$resume" = "y" ]; then
# Resume from last commit
last_commit=$(git log --oneline -1 --pretty=format:"%s")
echo "Last commit: $last_commit"
else
# Full reset
git reset HEAD
echo "Process reset"
fi
}
# Verify all changes committed
remaining_changes=$(git status --porcelain | wc -l)
if [ $remaining_changes -eq 0 ]; then
echo "✅ All changes committed"
else
echo "⚠️ Uncommitted changes remain:"
git status --short
fi
# Display commit history
echo "Created commits:"
git log --oneline -n 10 --graph
# Note: No automatic push
echo "📝 Note: Automatic push not performed"
echo "If needed, push with the following command:"
echo " git push origin $CURRENT_BRANCH"
# Get and classify all changed files
git diff HEAD --name-status | while read status file; do
echo "$status:$file"
done > /tmp/changes.txt
# Statistics of changes by functional directory
git diff HEAD --name-only | cut -d'/' -f1-2 | sort | uniq -c
# Directory-based grouping
GROUPS=$(git diff HEAD --name-only | cut -d'/' -f1-2 | sort | uniq)
for group in $GROUPS; do
echo "=== Group: $group ==="
git diff HEAD --name-only | grep "^$group" | head -10
done
# Analyze change type for each file
git diff HEAD --name-only | while read file; do
# Detect new function/class additions
NEW_FUNCTIONS=$(git diff HEAD -- "$file" | grep -c '^+.*function\|^+.*class\|^+.*def ')
# Detect bug fix patterns
BUG_FIXES=$(git diff HEAD -- "$file" | grep -c '^+.*fix\|^+.*bug\|^-.*error')
# Determine if test file
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
# Analyze import relationships
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
# Group related files
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 "Related files: $file <-> $related"
fi
done
# Adjust group size
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 "Commit $current_group: $file"
file_count=$((file_count + 1))
done
# Verify split results
for group in $(seq 1 $current_group); do
files=$(grep "Commit $group:" /tmp/commit_plan.txt | cut -d':' -f2-)
lines=$(echo "$files" | xargs git diff HEAD -- | wc -l)
echo "Commit $group: $(echo "$files" | wc -w) files, $lines lines changed"
done
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Required Types:
feat: New feature (user-visible feature addition)fix: Bug fixOptional Types:
build: Changes to build system or external dependencieschore: Other changes (no impact on release)ci: Changes to CI configuration files or scriptsdocs: Documentation-only changesstyle: Changes that do not affect code meaning (whitespace, formatting, semicolons, etc.)refactor: Code changes without bug fixes or feature additionsperf: Performance improvementstest: Adding or modifying testsIndicates the affected area of the change:
feat(api): add user authentication endpoint
fix(ui): resolve button alignment issue
docs(readme): update installation instructions
When there are breaking API changes:
feat!: change user API response format
or
feat(api)!: change authentication flow
Important: If project-specific conventions exist, they take precedence.
Automatically detect configuration from the following files:
commitlint.config.jscommitlint.config.mjscommitlint.config.cjscommitlint.config.ts.commitlintrc.js.commitlintrc.json.commitlintrc.yml.commitlintrc.yamlcommitlint section in package.json# Check example configuration files
cat commitlint.config.mjs
cat .commitlintrc.json
grep -A 10 '"commitlint"' package.json
Example of project-specific types:
// commitlint.config.mjs
export default {
extends: ["@commitlint/config-conventional"],
rules: {
"type-enum": [
2,
"always",
[
"feat",
"fix",
"docs",
"style",
"refactor",
"test",
"chore",
"wip", // Work in progress
"hotfix", // Emergency fix
"release", // Release
"deps", // Dependency update
"config", // Configuration change
],
],
},
};
// When project uses Japanese messages
export default {
rules: {
"subject-case": [0], // Disable for Japanese support
"subject-max-length": [2, "always", 72], // Adjust character limit for Japanese
},
};
Configuration File Search
find . -name "commitlint.config.*" -o -name ".commitlintrc.*" | head -1
Existing Commit Analysis
git log --oneline -50 --pretty=format:"%s"
Type Usage Statistics
git log --oneline -100 --pretty=format:"%s" | \
grep -oE '^[a-z]+(\([^)]+\))?' | \
sort | uniq -c | sort -nr
feat(scope): add new feature
fix(scope): fix bug
docs(scope): update documentation
✨ feat: add user registration
🐛 fix: resolve login issue
📚 docs: update API docs
feat: add user registration functionality
fix: resolve login process bug
docs: update API documentation
How we figure out your language:
Check CommitLint Settings for language configuration
# Determine Japanese if subject-case rule is disabled
grep -E '"subject-case".*\[0\]|subject-case.*0' commitlint.config.*
Git log analysis for automatic determination
# Analyze language of last 20 commits
git log --oneline -20 --pretty=format:"%s" | \
grep -E '^[\x{3040}-\x{30ff}]|[\x{4e00}-\x{9fff}]' | wc -l
# Japanese mode if over 50% are Japanese
Project files language settings
# Check README.md language
head -10 README.md | grep -E '^[\x{3040}-\x{30ff}]|[\x{4e00}-\x{9fff}]' | wc -l
# Check package.json description
grep -E '"description".*[\x{3040}-\x{30ff}]|[\x{4e00}-\x{9fff}]' package.json
Comments and strings analysis in changed files
# Check comment language in changed files
git diff HEAD | grep -E '^[+-].*//.*[\x{3040}-\x{30ff}]|[\x{4e00}-\x{9fff}]' | wc -l
# English version always uses English
LANGUAGE="en"
We check for config files in this order:
Search for CommitLint configuration files
# Search in this order, use first found file
commitlint.config.mjs
commitlint.config.js
commitlint.config.cjs
commitlint.config.ts
.commitlintrc.js
.commitlintrc.json
.commitlintrc.yml
.commitlintrc.yaml
package.json (commitlint section)
Parse configuration content
Analyze existing commit history
# Learn usage patterns from recent commits
git log --oneline -100 --pretty=format:"%s" | \
head -20
Standard commitlint.config.mjs:
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"]],
},
};
Japanese-compatible configuration:
export default {
extends: ["@commitlint/config-conventional"],
rules: {
"subject-case": [0], // Disable for Japanese
"subject-max-length": [2, "always", 72],
"type-enum": [
2,
"always",
["feat", "fix", "docs", "style", "refactor", "test", "chore"],
],
},
};
Configuration with custom types:
export default {
extends: ["@commitlint/config-conventional"],
rules: {
"type-enum": [
2,
"always",
[
"feat",
"fix",
"docs",
"style",
"refactor",
"test",
"chore",
"wip", // Work in Progress
"hotfix", // Emergency fix
"release", // Release preparation
"deps", // Dependency update
"config", // Configuration change
],
],
},
};
If no configuration file is found:
Automatic inference through git log analysis
# Extract types from last 100 commits
git log --oneline -100 --pretty=format:"%s" | \
grep -oE '^[a-z]+(\([^)]+\))?' | \
sort | uniq -c | sort -nr
Default to Conventional Commits standard
feat, fix, docs, style, refactor, perf, test, chore, build, ci
Language determination
git push yourselfgit stash for safetyWhen making commit messages, we follow this order:
CommitLint settings (highest priority)
commitlint.config.* filesExisting commit history (second priority)
Project type (third priority)
package.json → Node.js projectCargo.toml → Rust projectpom.xml → Java projectConventional Commits standard (fallback)
Automatic scope detection in Monorepo:
# Infer scopes from packages/ folder
ls packages/ | head -10
# → Propose api, ui, core, auth, etc. as scopes
Framework-specific conventions:
// For Angular projects
{
'scope-enum': [2, 'always', [
'animations', 'common', 'core', 'forms', 'http', 'platform-browser',
'platform-server', 'router', 'service-worker', 'upgrade'
]]
}
// For React projects
{
'scope-enum': [2, 'always', [
'components', 'hooks', 'utils', 'types', 'styles', 'api'
]]
}
Company/team-specific conventions:
// Common pattern in Japanese companies
{
'type-enum': [2, 'always', [
'feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore',
'wip', // Work in progress (for pull requests)
'hotfix', // Emergency fix
'release' // Release preparation
]],
'subject-case': [0], // Support Japanese
'subject-max-length': [2, 'always', 72] // Longer limit for Japanese
}
Before (one massive commit):
# Changed files (15 files, 850 lines changed)
src/auth/login.js # New
src/auth/register.js # New
src/auth/password.js # New
src/auth/types.js # New
src/api/auth-routes.js # New
src/middleware/auth.js # New
src/database/migrations/001_users.sql # New
src/database/models/user.js # New
tests/auth/login.test.js # New
tests/auth/register.test.js # New
tests/api/auth-routes.test.js # New
docs/authentication.md # New
package.json # Dependency addition
README.md # Usage addition
.env.example # Environment variable example
# Problematic conventional commit
feat: implement complete user authentication system with login, registration, password reset, API routes, database models, tests and documentation
After (split into 5 meaningful commits):
# Commit 1: Database foundation
feat(db): add user model and authentication schema
Included files:
- src/database/migrations/001_users.sql
- src/database/models/user.js
- src/auth/types.js
Reason: Database structure is the foundation for other features, committed first
# Commit 2: Authentication logic
feat(auth): implement core authentication functionality
Included files:
- src/auth/login.js
- src/auth/register.js
- src/auth/password.js
- src/middleware/auth.js
Reason: Core authentication business logic committed together
# Commit 3: API endpoints
feat(api): add authentication API routes
Included files:
- src/api/auth-routes.js
Reason: API layer depends on authentication logic, committed later
# Commit 4: Comprehensive tests
test(auth): add comprehensive authentication tests
Included files:
- tests/auth/login.test.js
- tests/auth/register.test.js
- tests/api/auth-routes.test.js
Reason: Tests added after implementation is complete
# Commit 5: Documentation and configuration
docs(auth): add authentication documentation and configuration
Included files:
- docs/authentication.md
- package.json
- README.md
- .env.example
Reason: Documentation and configuration committed together at the end
Before (problematic mixed commit):
# Changed files (8 files, 320 lines changed)
src/user/service.js # Bug fixes + Refactoring
src/user/validator.js # New (refactoring)
src/auth/middleware.js # Bug fix
src/api/user-routes.js # Bug fix + Error handling improvement
tests/user.test.js # Test addition
tests/auth.test.js # Bug fix test addition
docs/user-api.md # Documentation update
package.json # Dependency update
# Problematic commit
fix: resolve user validation bugs and refactor validation logic with improved error handling
After (split into 3 commits by type):
# Commit 1: Critical bug fixes
fix: resolve user validation and authentication bugs
Included files:
- src/user/service.js (bug fix portion only)
- src/auth/middleware.js
- tests/auth.test.js (bug fix tests only)
Reason: Production-affecting bugs fixed with highest priority
# Commit 2: Validation logic refactoring
refactor: extract and improve user validation logic
Included files:
- src/user/service.js (refactoring portion)
- src/user/validator.js
- src/api/user-routes.js
- tests/user.test.js
Reason: Structural improvements committed as functional units
# Commit 3: Documentation and dependency update
chore: update documentation and dependencies
Included files:
- docs/user-api.md
- package.json
Reason: Development environment improvements committed together at the end
Before (cross-functional massive commit):
# Changed files (12 files, 600 lines changed)
src/user/profile.js # New feature A
src/user/avatar.js # New feature A
src/notification/email.js # New feature B
src/notification/sms.js # New feature B
src/api/profile-routes.js # New feature A API
src/api/notification-routes.js # New feature B API
src/dashboard/widgets.js # New feature C
src/dashboard/charts.js # New feature C
tests/profile.test.js # New feature A tests
tests/notification.test.js # New feature B tests
tests/dashboard.test.js # New feature C tests
package.json # All features' dependencies
# Problematic commit
feat: add user profile management, notification system and dashboard widgets
After (split into 4 commits by feature):
# Commit 1: User profile feature
feat(profile): add user profile management
Included files:
- src/user/profile.js
- src/user/avatar.js
- src/api/profile-routes.js
- tests/profile.test.js
Reason: Profile feature is an independent functional unit
# Commit 2: Notification system
feat(notification): implement email and SMS notifications
Included files:
- src/notification/email.js
- src/notification/sms.js
- src/api/notification-routes.js
- tests/notification.test.js
Reason: Notification feature is an independent functional unit
# Commit 3: Dashboard widgets
feat(dashboard): add interactive widgets and charts
Included files:
- src/dashboard/widgets.js
- src/dashboard/charts.js
- tests/dashboard.test.js
Reason: Dashboard feature is an independent functional unit
# Commit 4: Dependencies and infrastructure update
chore: update dependencies for new features
Included files:
- package.json
Reason: Common dependency updates committed together at the end
| Item | Before (Massive Commit) | After (Proper Splitting) |
|---|---|---|
| Reviewability | ❌ Very difficult | ✅ Each commit is small and reviewable |
| Bug Tracking | ❌ Difficult to identify problem location | ✅ Problematic commits can be immediately identified |
| Reverting | ❌ Need to revert everything | ✅ Can pinpoint and revert only problematic parts |
| Parallel Development | ❌ Conflict-prone | ✅ Feature-based merging is easy |
| Deployment | ❌ All features deployed at once | ✅ Staged deployment possible |
--max-commits optionedit modenpx claudepluginhub wasabeef/claude-code-cookbook --plugin cook-enSplits large uncommitted changes into small, semantic commits grouped by functional boundaries, change type, or dependencies. Useful for maintaining clean git history.
Splits large changes into semantically meaningful small commits with appropriate messages. Activates on 'commit' or 'diviser et commiter'.
Splits large git changes into minimal semantic units and commits them sequentially with semantic messages. Useful for organizing messy working trees into clean commits.