Skip to content

Instantly share code, notes, and snippets.

@nicksteffens
Created March 17, 2026 15:20
Show Gist options
  • Select an option

  • Save nicksteffens/8e33f916930e252e9ade7a470d55cb8c to your computer and use it in GitHub Desktop.

Select an option

Save nicksteffens/8e33f916930e252e9ade7a470d55cb8c to your computer and use it in GitHub Desktop.
Git commit audit script - analyzes commit message quality by author
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