11#! /bin/bash
22
33# Claude Auto-Commit - AI-powered Git commit message generator
4- # Version: 0.0.3
4+ # Version: 0.0.4
55# Homepage: https://claude-auto-commit.0xkaz.com
66
7- VERSION=" 0.0.3 "
7+ VERSION=" 0.0.4 "
88REPO=" 0xkaz/claude-auto-commit"
99CONFIG_DIR=" $HOME /.claude-auto-commit"
1010CONFIG_FILE=" $CONFIG_DIR /config.yml"
@@ -23,6 +23,9 @@ UPDATE_FREQUENCY="daily"
2323SKIP_PUSH_CONFIRM=false
2424DRY_RUN=false
2525SHOW_SUMMARY=false
26+ SMART_GROUP=false
27+ ANALYZE_HISTORY=false
28+ USE_LEARNED_STYLE=false
2629
2730# Display usage information
2831usage () {
@@ -44,6 +47,9 @@ Options:
4447 -y, --yes Skip push confirmation
4548 --dry-run Generate message only (no commit)
4649 --summary Show detailed change summary
50+ --smart-group Group related files into logical commits
51+ --analyze-history Analyze commit history to learn patterns
52+ --style learned Use learned commit style from history
4753 --update Check for updates now
4854 --no-update Skip update check
4955 --version Show version information
@@ -54,6 +60,8 @@ Examples:
5460 $( basename $0 ) -m "Custom message" -n
5561 $( basename $0 ) -c -t fix -l en
5662 $( basename $0 ) --dry-run # Generate message only
63+ $( basename $0 ) --smart-group # Group related files
64+ $( basename $0 ) --analyze-history # Learn from commit history
5765EOF
5866}
5967
@@ -242,6 +250,20 @@ while [[ $# -gt 0 ]]; do
242250 SHOW_SUMMARY=true
243251 shift
244252 ;;
253+ --smart-group)
254+ SMART_GROUP=true
255+ shift
256+ ;;
257+ --analyze-history)
258+ ANALYZE_HISTORY=true
259+ shift
260+ ;;
261+ --style)
262+ if [ " $2 " = " learned" ]; then
263+ USE_LEARNED_STYLE=true
264+ fi
265+ shift 2
266+ ;;
245267 --update)
246268 # Force update
247269 AUTO_UPDATE=true
@@ -285,6 +307,64 @@ if ! git rev-parse --git-dir > /dev/null 2>&1; then
285307 exit 1
286308fi
287309
310+ # Analyze commit history if requested
311+ if [ " $ANALYZE_HISTORY " = true ]; then
312+ print_info " Analyzing commit history..."
313+
314+ # Get recent commits (last 100)
315+ COMMIT_COUNT=$( git rev-list --count HEAD 2> /dev/null || echo 0)
316+ ANALYZE_COUNT=$(( COMMIT_COUNT > 100 ? 100 : COMMIT_COUNT))
317+
318+ if [ " $COMMIT_COUNT " -eq 0 ]; then
319+ print_error " No commits found in repository"
320+ exit 1
321+ fi
322+
323+ # Analyze patterns
324+ echo
325+ print_info " 📊 Commit History Analysis (last $ANALYZE_COUNT commits)"
326+ echo
327+
328+ # Emoji usage
329+ EMOJI_COUNT=$( git log --oneline -n $ANALYZE_COUNT | grep -E " ^[a-f0-9]+ [🎯🚀💡🔧🐛📝✨🎨⚡️🔥💄🎉✅🚧🚨♻️➕➖🔀📦🍱🏷️🌐💬🗃️🔊🔇📱💻🎨⚗️🔍🥅🩹🔨📌⬆️⬇️]" | wc -l)
330+ EMOJI_PERCENT=$(( EMOJI_COUNT * 100 / ANALYZE_COUNT))
331+ echo " 📊 Emoji usage: $EMOJI_PERCENT % ($EMOJI_COUNT /$ANALYZE_COUNT commits)"
332+
333+ # Average message length
334+ AVG_LENGTH=$( git log --oneline -n $ANALYZE_COUNT | awk ' {$1=""; print length($0)}' | awk ' {sum+=$1} END {print int(sum/NR)}' )
335+ echo " 📏 Average message length: $AVG_LENGTH characters"
336+
337+ # Common prefixes
338+ echo " 🏷️ Common prefixes:"
339+ git log --oneline -n $ANALYZE_COUNT | sed ' s/^[a-f0-9]* //' | grep -oE " ^(feat|fix|docs|style|refactor|test|chore|build|ci|perf|revert|wip|hotfix|release):" | sort | uniq -c | sort -rn | head -5 | while read count prefix; do
340+ echo " $prefix $count times"
341+ done
342+
343+ # Language detection (simplified for macOS compatibility)
344+ echo " 🌐 Detected languages:"
345+ # For macOS, use a simpler approach
346+ JAPANESE_COUNT=$( git log --oneline -n $ANALYZE_COUNT | grep -E " [ぁ-んァ-ヶー一-龠]" | wc -l | tr -d ' ' )
347+ ENGLISH_COUNT=$(( ANALYZE_COUNT - JAPANESE_COUNT))
348+ [ " $JAPANESE_COUNT " -gt 0 ] && echo " Japanese: $(( JAPANESE_COUNT * 100 / ANALYZE_COUNT)) % ($JAPANESE_COUNT commits)"
349+ [ " $ENGLISH_COUNT " -gt 0 ] && echo " English: $(( ENGLISH_COUNT * 100 / ANALYZE_COUNT)) % ($ENGLISH_COUNT commits)"
350+
351+ # Save analysis results
352+ cat > " $CONFIG_DIR /commit-style.yml" << EOF
353+ # Learned commit style from history analysis
354+ commit_style:
355+ emoji_usage: $EMOJI_PERCENT
356+ average_length: $AVG_LENGTH
357+ analyzed_commits: $ANALYZE_COUNT
358+ analysis_date: $( date -u +" %Y-%m-%d %H:%M:%S UTC" )
359+ EOF
360+
361+ echo
362+ print_success " Analysis complete! Results saved to $CONFIG_DIR /commit-style.yml"
363+ echo
364+ print_info " Use '--style learned' to apply these patterns to new commits"
365+ exit 0
366+ fi
367+
288368# Get current branch
289369CURRENT_BRANCH=$( git branch --show-current)
290370print_info " Current branch: $CURRENT_BRANCH "
@@ -311,6 +391,62 @@ echo " Staged: $STAGED_COUNT files"
311391echo " Unstaged: $UNSTAGED_COUNT files"
312392echo " Untracked: $UNTRACKED_COUNT files"
313393
394+ # Smart grouping if requested
395+ if [ " $SMART_GROUP " = true ]; then
396+ echo
397+ print_info " 🎯 Analyzing file changes for logical grouping..."
398+
399+ # Get all changed files
400+ ALL_CHANGED_FILES=$( git diff --name-only; git diff --cached --name-only; git ls-files --others --exclude-standard)
401+
402+ # Analyze file patterns (simplified for compatibility)
403+ echo
404+ print_info " File categories detected:"
405+
406+ # Frontend/JS files
407+ FRONTEND_FILES=$( echo " $ALL_CHANGED_FILES " | grep -E " ^(src|lib|app)/.*\.(js|ts|jsx|tsx)$" | wc -l | tr -d ' ' )
408+ [ " $FRONTEND_FILES " -gt 0 ] && echo " 🎯 Frontend/Application: $FRONTEND_FILES files"
409+
410+ # Backend files
411+ BACKEND_FILES=$( echo " $ALL_CHANGED_FILES " | grep -E " ^(api|server|backend)/.*" | wc -l | tr -d ' ' )
412+ [ " $BACKEND_FILES " -gt 0 ] && echo " 🔧 Backend/API: $BACKEND_FILES files"
413+
414+ # Test files
415+ TEST_FILES=$( echo " $ALL_CHANGED_FILES " | grep -E " ^(test|spec|__tests__)/.*" | wc -l | tr -d ' ' )
416+ [ " $TEST_FILES " -gt 0 ] && echo " 🧪 Tests: $TEST_FILES files"
417+
418+ # Documentation
419+ DOC_FILES=$( echo " $ALL_CHANGED_FILES " | grep -E " ^(docs?|README|CONTRIBUTING|CHANGELOG)" | wc -l | tr -d ' ' )
420+ [ " $DOC_FILES " -gt 0 ] && echo " 📖 Documentation: $DOC_FILES files"
421+
422+ # Config files
423+ CONFIG_FILES=$( echo " $ALL_CHANGED_FILES " | grep -E " ^(\.github|\.gitlab|\.|config)" | wc -l | tr -d ' ' )
424+ [ " $CONFIG_FILES " -gt 0 ] && echo " ⚙️ Configuration: $CONFIG_FILES files"
425+
426+ # Style files
427+ STYLE_FILES=$( echo " $ALL_CHANGED_FILES " | grep -E " \.(css|scss|sass|less|styl)$" | wc -l | tr -d ' ' )
428+ [ " $STYLE_FILES " -gt 0 ] && echo " 🎨 Styles: $STYLE_FILES files"
429+
430+ if [ " $VERBOSE " = true ]; then
431+ echo
432+ echo " Files by directory:"
433+ echo " $ALL_CHANGED_FILES " | cut -d' /' -f1 | sort | uniq -c | sort -rn | head -10 | while read count dir; do
434+ [ -n " $dir " ] && echo " $dir /: $count files"
435+ done
436+ fi
437+
438+ echo
439+ read -p " Select groups to commit (e.g., 1,3 or 'all' or 'skip'): " -r GROUP_SELECTION
440+
441+ if [ " $GROUP_SELECTION " = " skip" ]; then
442+ print_info " Smart grouping skipped. Proceeding with normal commit..."
443+ elif [ " $GROUP_SELECTION " != " all" ] && [ -n " $GROUP_SELECTION " ]; then
444+ # TODO: Implement selective group commit
445+ print_warning " Selective group commit not yet implemented. Proceeding with all changes..."
446+ fi
447+ echo
448+ fi
449+
314450# Show detailed summary
315451if [ " $SHOW_SUMMARY " = true ]; then
316452 echo
@@ -393,6 +529,24 @@ The commit message should be concise and capture the essence of the changes."
393529The commit message should be concise and capture the essence of the changes."
394530 fi
395531
532+ # Apply learned style if requested
533+ if [ " $USE_LEARNED_STYLE " = true ] && [ -f " $CONFIG_DIR /commit-style.yml" ]; then
534+ # Read learned style
535+ LEARNED_EMOJI=$( grep " emoji_usage:" " $CONFIG_DIR /commit-style.yml" | awk ' {print $2}' )
536+ LEARNED_LENGTH=$( grep " average_length:" " $CONFIG_DIR /commit-style.yml" | awk ' {print $2}' )
537+
538+ PROMPT=" $PROMPT
539+
540+ Based on commit history analysis:
541+ - Use emoji in ${LEARNED_EMOJI} % of cases
542+ - Target message length: around ${LEARNED_LENGTH} characters"
543+
544+ # Override emoji setting based on learned pattern
545+ if [ " $LEARNED_EMOJI " -gt 50 ]; then
546+ USE_EMOJI=true
547+ fi
548+ fi
549+
396550 # Emoji settings
397551 if [ " $USE_EMOJI " = true ]; then
398552 PROMPT=" $PROMPT
0 commit comments