Created
March 17, 2026 15:20
-
-
Save nicksteffens/8e33f916930e252e9ade7a470d55cb8c to your computer and use it in GitHub Desktop.
Git commit audit script - analyzes commit message quality by author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import sys | |
| import re | |
| from collections import Counter | |
| CONVENTIONAL_RE = re.compile( | |
| r'^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.+?\))?!?:\s' | |
| ) | |
| BAD_PATTERNS = { | |
| 'too_short': lambda s: len(s.strip()) <= 10, | |
| 'vague_wip': lambda s: s.strip().lower() in ('wip', 'mend', 'fix', 'update', 'changes', 'stuff', 'typo', 'prettier', 'prettifer'), | |
| 'starts_with_wip': lambda s: s.strip().lower().startswith('wip') and len(s.strip()) < 30, | |
| 'no_context': lambda s: re.match(r'^(fix|update|add|remove|change)\s*$', s.strip(), re.I) is not None, | |
| 'first_line_too_long': lambda s: len(s.strip()) > 100, | |
| } | |
| def classify(msg): | |
| issues = [] | |
| m = msg.strip() | |
| # Check conventional commit | |
| is_conventional = bool(CONVENTIONAL_RE.match(m)) | |
| # Check bad patterns | |
| if BAD_PATTERNS['too_short'](m): | |
| issues.append('too_short') | |
| if BAD_PATTERNS['vague_wip'](m): | |
| issues.append('vague/wip') | |
| elif BAD_PATTERNS['starts_with_wip'](m): | |
| issues.append('starts_with_wip') | |
| if BAD_PATTERNS['first_line_too_long'](m): | |
| issues.append('too_long') | |
| # Non-conventional and not clearly descriptive | |
| if not is_conventional and not m.startswith('Merge') and not m.startswith('Revert'): | |
| # Check if it's at least somewhat descriptive (has a verb + noun pattern) | |
| words = m.split() | |
| if len(words) <= 2 and not any(w in ('README.md',) for w in words): | |
| issues.append('unclear') | |
| return is_conventional, issues | |
| lines = sys.stdin.read().strip().split('\n') | |
| lines = [l for l in lines if l.strip()] | |
| total = len(lines) | |
| conventional_count = 0 | |
| flagged = [] | |
| issue_counts = Counter() | |
| for msg in lines: | |
| is_conv, issues = classify(msg) | |
| if is_conv: | |
| conventional_count += 1 | |
| if issues: | |
| flagged.append((msg, issues)) | |
| for i in issues: | |
| issue_counts[i] += 1 | |
| print(f"## Commit Audit: Eric Cook") | |
| print(f"") | |
| print(f"**Total non-merge commits:** {total}") | |
| print(f"**Conventional commits:** {conventional_count} ({conventional_count*100//total}%)") | |
| print(f"**Non-conventional:** {total - conventional_count} ({(total-conventional_count)*100//total}%)") | |
| print(f"**Flagged messages:** {len(flagged)} ({len(flagged)*100//total}%)") | |
| print() | |
| print(f"### Issue Breakdown") | |
| print(f"| Issue | Count |") | |
| print(f"|-------|-------|") | |
| for issue, count in issue_counts.most_common(): | |
| print(f"| {issue} | {count} |") | |
| print() | |
| print(f"### Flagged Commits (sample)") | |
| print(f"| Message | Issues |") | |
| print(f"|---------|--------|") | |
| for msg, issues in flagged[:30]: | |
| safe = msg.replace('|', '\\|')[:80] | |
| print(f"| `{safe}` | {', '.join(issues)} |") | |
| if len(flagged) > 30: | |
| print(f"| ... and {len(flagged)-30} more | |") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment