Initial commit
This commit is contained in:
259
commands/commit-best-practices/.scripts/amend-safety.sh
Executable file
259
commands/commit-best-practices/.scripts/amend-safety.sh
Executable file
@@ -0,0 +1,259 @@
|
||||
#!/usr/bin/env bash
|
||||
################################################################################
|
||||
# Amend Safety Checker Script
|
||||
#
|
||||
# Purpose: Check if it's safe to amend the last commit
|
||||
# Version: 1.0.0
|
||||
# Usage: ./amend-safety.sh
|
||||
# Returns: JSON with safety analysis
|
||||
# Exit Codes:
|
||||
# 0 = Safe to amend
|
||||
# 1 = Unsafe to amend
|
||||
# 2 = Warning (proceed with caution)
|
||||
################################################################################
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
################################################################################
|
||||
# Check if commit is pushed to remote
|
||||
################################################################################
|
||||
check_not_pushed() {
|
||||
local status="fail"
|
||||
local message=""
|
||||
|
||||
# Check if we have upstream tracking
|
||||
if ! git rev-parse --abbrev-ref --symbolic-full-name @{upstream} &>/dev/null; then
|
||||
status="pass"
|
||||
message="No upstream branch (commit is local only)"
|
||||
else
|
||||
# Check if HEAD commit exists on upstream
|
||||
local upstream_branch
|
||||
upstream_branch=$(git rev-parse --abbrev-ref --symbolic-full-name @{upstream})
|
||||
|
||||
# Get commits that are local only
|
||||
local local_commits
|
||||
local_commits=$(git log "$upstream_branch"..HEAD --oneline 2>/dev/null || echo "")
|
||||
|
||||
if [[ -n "$local_commits" ]]; then
|
||||
status="pass"
|
||||
message="Commit not pushed to $upstream_branch"
|
||||
else
|
||||
status="fail"
|
||||
message="Commit already pushed to $upstream_branch"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "{\"status\": \"$status\", \"message\": \"$message\"}"
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Check if current user is the commit author
|
||||
################################################################################
|
||||
check_same_author() {
|
||||
local status="fail"
|
||||
local message=""
|
||||
|
||||
# Get current user email
|
||||
local current_user
|
||||
current_user=$(git config user.email)
|
||||
|
||||
# Get last commit author email
|
||||
local commit_author
|
||||
commit_author=$(git log -1 --format='%ae')
|
||||
|
||||
if [[ "$current_user" == "$commit_author" ]]; then
|
||||
status="pass"
|
||||
message="You are the commit author"
|
||||
else
|
||||
status="fail"
|
||||
message="Different author: $commit_author (you are $current_user)"
|
||||
fi
|
||||
|
||||
echo "{\"status\": \"$status\", \"message\": \"$message\"}"
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Check if on a safe branch (not main/master)
|
||||
################################################################################
|
||||
check_safe_branch() {
|
||||
local status="pass"
|
||||
local message=""
|
||||
|
||||
# Get current branch
|
||||
local branch
|
||||
branch=$(git branch --show-current)
|
||||
|
||||
# List of protected branches
|
||||
local protected_branches=("main" "master" "develop" "production" "release")
|
||||
|
||||
for protected in "${protected_branches[@]}"; do
|
||||
if [[ "$branch" == "$protected" ]]; then
|
||||
status="warn"
|
||||
message="On protected branch: $branch (amending discouraged)"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$status" == "pass" ]]; then
|
||||
message="On feature branch: $branch"
|
||||
fi
|
||||
|
||||
echo "{\"status\": \"$status\", \"message\": \"$message\"}"
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Check if collaborators might have this commit
|
||||
################################################################################
|
||||
check_collaborators() {
|
||||
local status="pass"
|
||||
local message="Solo work on branch"
|
||||
|
||||
# This is a heuristic check - actual collaboration is hard to detect
|
||||
# We check if:
|
||||
# 1. Remote branch exists
|
||||
# 2. There are other commits on the remote not in local
|
||||
|
||||
if git rev-parse --abbrev-ref --symbolic-full-name @{upstream} &>/dev/null; then
|
||||
local upstream_branch
|
||||
upstream_branch=$(git rev-parse --abbrev-ref --symbolic-full-name @{upstream})
|
||||
|
||||
# Check if there are remote commits we don't have
|
||||
local remote_commits
|
||||
remote_commits=$(git log HEAD.."$upstream_branch" --oneline 2>/dev/null || echo "")
|
||||
|
||||
if [[ -n "$remote_commits" ]]; then
|
||||
status="warn"
|
||||
message="Remote has commits you don't have - possible collaboration"
|
||||
else
|
||||
# Check if branch is shared (exists on remote)
|
||||
local remote_name
|
||||
remote_name=$(echo "$upstream_branch" | cut -d/ -f1)
|
||||
|
||||
local branch_name
|
||||
branch_name=$(git branch --show-current)
|
||||
|
||||
if git ls-remote --heads "$remote_name" "$branch_name" | grep -q "$branch_name"; then
|
||||
status="warn"
|
||||
message="Branch exists on remote - collaborators may have pulled"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "{\"status\": \"$status\", \"message\": \"$message\"}"
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Determine overall recommendation
|
||||
################################################################################
|
||||
determine_recommendation() {
|
||||
local not_pushed="$1"
|
||||
local same_author="$2"
|
||||
local safe_branch="$3"
|
||||
local collaborators="$4"
|
||||
|
||||
# UNSAFE conditions (critical failures)
|
||||
if [[ "$not_pushed" == "fail" ]] || [[ "$same_author" == "fail" ]]; then
|
||||
echo "unsafe"
|
||||
return
|
||||
fi
|
||||
|
||||
# WARNING conditions (proceed with caution)
|
||||
if [[ "$safe_branch" == "warn" ]] || [[ "$collaborators" == "warn" ]]; then
|
||||
echo "warning"
|
||||
return
|
||||
fi
|
||||
|
||||
# SAFE (all checks pass)
|
||||
echo "safe"
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Main execution
|
||||
################################################################################
|
||||
main() {
|
||||
# Verify we're in a git repository
|
||||
if ! git rev-parse --git-dir &>/dev/null; then
|
||||
echo "{\"error\": \"Not a git repository\"}"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Check if there are any commits
|
||||
if ! git rev-parse HEAD &>/dev/null 2>&1; then
|
||||
echo "{\"error\": \"No commits to amend (empty repository)\"}"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Run all checks
|
||||
local not_pushed_result
|
||||
local same_author_result
|
||||
local safe_branch_result
|
||||
local collaborators_result
|
||||
|
||||
not_pushed_result=$(check_not_pushed)
|
||||
same_author_result=$(check_same_author)
|
||||
safe_branch_result=$(check_safe_branch)
|
||||
collaborators_result=$(check_collaborators)
|
||||
|
||||
# Extract status values for recommendation
|
||||
local not_pushed_status
|
||||
local same_author_status
|
||||
local safe_branch_status
|
||||
local collaborators_status
|
||||
|
||||
not_pushed_status=$(echo "$not_pushed_result" | grep -o '"status": "[^"]*"' | cut -d'"' -f4)
|
||||
same_author_status=$(echo "$same_author_result" | grep -o '"status": "[^"]*"' | cut -d'"' -f4)
|
||||
safe_branch_status=$(echo "$safe_branch_result" | grep -o '"status": "[^"]*"' | cut -d'"' -f4)
|
||||
collaborators_status=$(echo "$collaborators_result" | grep -o '"status": "[^"]*"' | cut -d'"' -f4)
|
||||
|
||||
# Determine overall recommendation
|
||||
local recommendation
|
||||
recommendation=$(determine_recommendation "$not_pushed_status" "$same_author_status" "$safe_branch_status" "$collaborators_status")
|
||||
|
||||
# Determine safe boolean
|
||||
local safe="false"
|
||||
if [[ "$recommendation" == "safe" ]]; then
|
||||
safe="true"
|
||||
fi
|
||||
|
||||
# Get commit info
|
||||
local commit_sha
|
||||
local commit_author
|
||||
local branch
|
||||
|
||||
commit_sha=$(git rev-parse --short HEAD)
|
||||
commit_author=$(git log -1 --format='%an <%ae>')
|
||||
branch=$(git branch --show-current)
|
||||
|
||||
# Build JSON output
|
||||
cat <<EOF
|
||||
{
|
||||
"safe": $safe,
|
||||
"recommendation": "$recommendation",
|
||||
"commit": "$commit_sha",
|
||||
"author": "$commit_author",
|
||||
"branch": "$branch",
|
||||
"checks": {
|
||||
"not_pushed": $not_pushed_result,
|
||||
"same_author": $same_author_result,
|
||||
"safe_branch": $safe_branch_result,
|
||||
"collaborators": $collaborators_result
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Exit with appropriate code
|
||||
case "$recommendation" in
|
||||
safe)
|
||||
exit 0
|
||||
;;
|
||||
warning)
|
||||
exit 2
|
||||
;;
|
||||
unsafe)
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Execute main function
|
||||
main "$@"
|
||||
345
commands/commit-best-practices/.scripts/commit-reviewer.py
Executable file
345
commands/commit-best-practices/.scripts/commit-reviewer.py
Executable file
@@ -0,0 +1,345 @@
|
||||
#!/usr/bin/env python3
|
||||
################################################################################
|
||||
# Commit Reviewer Script
|
||||
#
|
||||
# Purpose: Analyze commit quality including message, changes, and atomicity
|
||||
# Version: 1.0.0
|
||||
# Usage: ./commit-reviewer.py <commit-sha>
|
||||
# Returns: JSON with comprehensive quality analysis
|
||||
# Exit Codes:
|
||||
# 0 = Success
|
||||
# 1 = Commit not found
|
||||
# 2 = Script execution error
|
||||
################################################################################
|
||||
|
||||
import sys
|
||||
import json
|
||||
import subprocess
|
||||
import re
|
||||
from typing import Dict, List, Tuple, Any
|
||||
|
||||
################################################################################
|
||||
# Git operations
|
||||
################################################################################
|
||||
|
||||
def git_command(args: List[str]) -> str:
|
||||
"""Execute git command and return output"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['git'] + args,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
)
|
||||
return result.stdout.strip()
|
||||
except subprocess.CalledProcessError as e:
|
||||
return ""
|
||||
|
||||
def commit_exists(sha: str) -> bool:
|
||||
"""Check if commit exists"""
|
||||
result = git_command(['rev-parse', '--verify', sha])
|
||||
return bool(result)
|
||||
|
||||
def get_commit_info(sha: str) -> Dict[str, str]:
|
||||
"""Get commit metadata"""
|
||||
return {
|
||||
'sha': git_command(['rev-parse', sha]),
|
||||
'author': git_command(['log', '-1', '--format=%an <%ae>', sha]),
|
||||
'date': git_command(['log', '-1', '--format=%ad', '--date=short', sha]),
|
||||
'subject': git_command(['log', '-1', '--format=%s', sha]),
|
||||
'body': git_command(['log', '-1', '--format=%b', sha]),
|
||||
}
|
||||
|
||||
def get_commit_stats(sha: str) -> Dict[str, int]:
|
||||
"""Get commit statistics"""
|
||||
stats_raw = git_command(['show', '--stat', '--format=', sha])
|
||||
|
||||
files_changed = 0
|
||||
insertions = 0
|
||||
deletions = 0
|
||||
test_files = 0
|
||||
doc_files = 0
|
||||
|
||||
for line in stats_raw.split('\n'):
|
||||
if '|' in line:
|
||||
files_changed += 1
|
||||
filename = line.split('|')[0].strip()
|
||||
|
||||
# Count test files
|
||||
if 'test' in filename.lower() or 'spec' in filename.lower():
|
||||
test_files += 1
|
||||
|
||||
# Count doc files
|
||||
if filename.endswith('.md') or 'doc' in filename.lower():
|
||||
doc_files += 1
|
||||
|
||||
# Parse summary line: "5 files changed, 234 insertions(+), 12 deletions(-)"
|
||||
if 'insertion' in line:
|
||||
match = re.search(r'(\d+) insertion', line)
|
||||
if match:
|
||||
insertions = int(match.group(1))
|
||||
|
||||
if 'deletion' in line:
|
||||
match = re.search(r'(\d+) deletion', line)
|
||||
if match:
|
||||
deletions = int(match.group(1))
|
||||
|
||||
return {
|
||||
'files_changed': files_changed,
|
||||
'insertions': insertions,
|
||||
'deletions': deletions,
|
||||
'test_files': test_files,
|
||||
'doc_files': doc_files,
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Message analysis
|
||||
################################################################################
|
||||
|
||||
def analyze_message(subject: str, body: str) -> Dict[str, Any]:
|
||||
"""Analyze commit message quality"""
|
||||
|
||||
# Check conventional commits format
|
||||
conventional_pattern = r'^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([a-z0-9\-]+\))?: .+'
|
||||
is_conventional = bool(re.match(conventional_pattern, subject, re.IGNORECASE))
|
||||
|
||||
# Extract type and scope if conventional
|
||||
commit_type = None
|
||||
commit_scope = None
|
||||
|
||||
if is_conventional:
|
||||
match = re.match(r'^([a-z]+)(?:\(([a-z0-9\-]+)\))?: ', subject, re.IGNORECASE)
|
||||
if match:
|
||||
commit_type = match.group(1).lower()
|
||||
commit_scope = match.group(2) if match.group(2) else None
|
||||
|
||||
# Check subject length
|
||||
subject_length = len(subject)
|
||||
subject_ok = subject_length <= 50
|
||||
|
||||
# Check imperative mood (basic heuristics)
|
||||
imperative_verbs = ['add', 'fix', 'update', 'remove', 'refactor', 'improve', 'implement']
|
||||
past_tense_patterns = ['added', 'fixed', 'updated', 'removed', 'refactored', 'improved', 'implemented']
|
||||
|
||||
subject_lower = subject.lower()
|
||||
uses_imperative = any(subject_lower.startswith(verb) for verb in imperative_verbs)
|
||||
uses_past_tense = any(pattern in subject_lower for pattern in past_tense_patterns)
|
||||
|
||||
# Check if body exists and is useful
|
||||
has_body = bool(body.strip())
|
||||
body_lines = body.strip().split('\n') if has_body else []
|
||||
body_line_count = len([line for line in body_lines if line.strip()])
|
||||
|
||||
# Body quality assessment
|
||||
has_explanation = body_line_count > 2
|
||||
uses_bullets = any(line.strip().startswith(('-', '*', '•')) for line in body_lines)
|
||||
|
||||
return {
|
||||
'subject': subject,
|
||||
'body': body if has_body else None,
|
||||
'subject_length': subject_length,
|
||||
'subject_ok': subject_ok,
|
||||
'has_body': has_body,
|
||||
'body_line_count': body_line_count,
|
||||
'conventional': is_conventional,
|
||||
'type': commit_type,
|
||||
'scope': commit_scope,
|
||||
'imperative': uses_imperative and not uses_past_tense,
|
||||
'explanation': has_explanation,
|
||||
'uses_bullets': uses_bullets,
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Atomicity analysis
|
||||
################################################################################
|
||||
|
||||
def analyze_atomicity(sha: str, stats: Dict[str, int]) -> Dict[str, Any]:
|
||||
"""Analyze if commit is atomic"""
|
||||
|
||||
# Get changed files
|
||||
changed_files = git_command(['show', '--name-only', '--format=', sha]).split('\n')
|
||||
changed_files = [f for f in changed_files if f.strip()]
|
||||
|
||||
# Analyze file types
|
||||
file_types = set()
|
||||
scopes = set()
|
||||
|
||||
for filepath in changed_files:
|
||||
# Determine file type
|
||||
if 'test' in filepath.lower() or 'spec' in filepath.lower():
|
||||
file_types.add('test')
|
||||
elif filepath.endswith('.md') or 'doc' in filepath.lower():
|
||||
file_types.add('docs')
|
||||
elif any(filepath.endswith(ext) for ext in ['.js', '.ts', '.py', '.go', '.rs', '.java']):
|
||||
file_types.add('code')
|
||||
elif any(filepath.endswith(ext) for ext in ['.json', '.yaml', '.yml', '.toml']):
|
||||
file_types.add('config')
|
||||
|
||||
# Determine scope from path
|
||||
parts = filepath.split('/')
|
||||
if len(parts) > 1:
|
||||
scopes.add(parts[0])
|
||||
|
||||
# Check for multiple types (excluding test + code as acceptable)
|
||||
suspicious_type_mix = False
|
||||
if 'docs' in file_types and 'code' in file_types:
|
||||
suspicious_type_mix = True
|
||||
if 'config' in file_types and len(file_types) > 2:
|
||||
suspicious_type_mix = True
|
||||
|
||||
# Check for multiple scopes
|
||||
multiple_scopes = len(scopes) > 2
|
||||
|
||||
# Size check (too large likely non-atomic)
|
||||
too_large = stats['files_changed'] > 15 or stats['insertions'] > 500
|
||||
|
||||
# Determine atomicity
|
||||
is_atomic = not (suspicious_type_mix or multiple_scopes or too_large)
|
||||
|
||||
issues = []
|
||||
if suspicious_type_mix:
|
||||
issues.append(f"Mixes {' and '.join(file_types)}")
|
||||
if multiple_scopes:
|
||||
issues.append(f"Affects multiple scopes: {', '.join(sorted(scopes))}")
|
||||
if too_large:
|
||||
issues.append(f"Large commit: {stats['files_changed']} files")
|
||||
|
||||
return {
|
||||
'atomic': is_atomic,
|
||||
'file_types': sorted(file_types),
|
||||
'scopes': sorted(scopes),
|
||||
'issues': issues,
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Quality scoring
|
||||
################################################################################
|
||||
|
||||
def calculate_score(message: Dict[str, Any], stats: Dict[str, int], atomicity: Dict[str, Any]) -> Tuple[int, str, List[str]]:
|
||||
"""Calculate overall quality score (0-100)"""
|
||||
|
||||
score = 100
|
||||
issues = []
|
||||
|
||||
# Message quality (40 points)
|
||||
if not message['conventional']:
|
||||
score -= 10
|
||||
issues.append("Not using conventional commits format")
|
||||
|
||||
if not message['subject_ok']:
|
||||
score -= 5
|
||||
issues.append(f"Subject too long ({message['subject_length']} chars, should be ≤50)")
|
||||
|
||||
if not message['imperative']:
|
||||
score -= 5
|
||||
issues.append("Subject not in imperative mood")
|
||||
|
||||
if not message['has_body'] and stats['files_changed'] > 3:
|
||||
score -= 10
|
||||
issues.append("No commit body explaining changes")
|
||||
elif message['has_body'] and not message['explanation']:
|
||||
score -= 5
|
||||
issues.append("Commit body too brief")
|
||||
|
||||
# Atomicity (30 points)
|
||||
if not atomicity['atomic']:
|
||||
score -= 20
|
||||
issues.extend(atomicity['issues'])
|
||||
|
||||
# Test coverage (20 points)
|
||||
has_code_changes = 'code' in atomicity['file_types']
|
||||
has_test_changes = stats['test_files'] > 0
|
||||
|
||||
if has_code_changes and not has_test_changes and stats['insertions'] > 100:
|
||||
score -= 15
|
||||
issues.append("No tests included for significant code changes")
|
||||
elif has_code_changes and not has_test_changes:
|
||||
score -= 5
|
||||
issues.append("No tests included")
|
||||
|
||||
# Size appropriateness (10 points)
|
||||
if stats['files_changed'] > 20:
|
||||
score -= 5
|
||||
issues.append(f"Very large commit ({stats['files_changed']} files)")
|
||||
|
||||
if stats['insertions'] > 1000:
|
||||
score -= 5
|
||||
issues.append(f"Very large changeset ({stats['insertions']} insertions)")
|
||||
|
||||
# Determine quality level
|
||||
if score >= 90:
|
||||
quality = "excellent"
|
||||
elif score >= 70:
|
||||
quality = "good"
|
||||
elif score >= 50:
|
||||
quality = "fair"
|
||||
else:
|
||||
quality = "poor"
|
||||
|
||||
return max(0, score), quality, issues
|
||||
|
||||
################################################################################
|
||||
# Main execution
|
||||
################################################################################
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print(json.dumps({"error": "Usage: commit-reviewer.py <commit-sha>"}))
|
||||
sys.exit(2)
|
||||
|
||||
commit_sha = sys.argv[1]
|
||||
|
||||
# Check if git repository
|
||||
if not git_command(['rev-parse', '--git-dir']):
|
||||
print(json.dumps({"error": "Not a git repository"}))
|
||||
sys.exit(2)
|
||||
|
||||
# Check if commit exists
|
||||
if not commit_exists(commit_sha):
|
||||
print(json.dumps({"error": f"Commit not found: {commit_sha}"}))
|
||||
sys.exit(1)
|
||||
|
||||
# Gather commit information
|
||||
info = get_commit_info(commit_sha)
|
||||
stats = get_commit_stats(commit_sha)
|
||||
message_analysis = analyze_message(info['subject'], info['body'])
|
||||
atomicity_analysis = analyze_atomicity(commit_sha, stats)
|
||||
|
||||
# Calculate quality score
|
||||
score, quality, issues = calculate_score(message_analysis, stats, atomicity_analysis)
|
||||
|
||||
# Build output
|
||||
output = {
|
||||
'commit': info['sha'][:8],
|
||||
'author': info['author'],
|
||||
'date': info['date'],
|
||||
'message': {
|
||||
'subject': message_analysis['subject'],
|
||||
'body': message_analysis['body'],
|
||||
'subject_length': message_analysis['subject_length'],
|
||||
'has_body': message_analysis['has_body'],
|
||||
'conventional': message_analysis['conventional'],
|
||||
'type': message_analysis['type'],
|
||||
'scope': message_analysis['scope'],
|
||||
},
|
||||
'changes': {
|
||||
'files_changed': stats['files_changed'],
|
||||
'insertions': stats['insertions'],
|
||||
'deletions': stats['deletions'],
|
||||
'test_files': stats['test_files'],
|
||||
'doc_files': stats['doc_files'],
|
||||
},
|
||||
'quality': {
|
||||
'atomic': atomicity_analysis['atomic'],
|
||||
'message_quality': quality,
|
||||
'test_coverage': stats['test_files'] > 0,
|
||||
'issues': issues,
|
||||
},
|
||||
'score': score,
|
||||
}
|
||||
|
||||
print(json.dumps(output, indent=2))
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
322
commands/commit-best-practices/.scripts/pre-commit-check.sh
Executable file
322
commands/commit-best-practices/.scripts/pre-commit-check.sh
Executable file
@@ -0,0 +1,322 @@
|
||||
#!/usr/bin/env bash
|
||||
################################################################################
|
||||
# Pre-Commit Validation Script
|
||||
#
|
||||
# Purpose: Run comprehensive pre-commit checks to ensure code quality
|
||||
# Version: 1.0.0
|
||||
# Usage: ./pre-commit-check.sh [quick:true|false]
|
||||
# Returns: JSON with validation results
|
||||
# Exit Codes:
|
||||
# 0 = All checks passed
|
||||
# 1 = One or more checks failed
|
||||
# 2 = Script execution error
|
||||
################################################################################
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Default to full validation
|
||||
QUICK_MODE="${1:-quick:false}"
|
||||
QUICK_MODE="${QUICK_MODE#quick:}"
|
||||
|
||||
# Initialize results
|
||||
OVERALL_STATUS="pass"
|
||||
declare -A RESULTS
|
||||
|
||||
################################################################################
|
||||
# Check if tests pass
|
||||
################################################################################
|
||||
check_tests() {
|
||||
local status="skip"
|
||||
local message="Tests skipped in quick mode"
|
||||
|
||||
if [[ "$QUICK_MODE" != "true" ]]; then
|
||||
# Detect test framework and run tests
|
||||
if [[ -f "package.json" ]] && grep -q "\"test\":" package.json; then
|
||||
if npm test &>/dev/null; then
|
||||
status="pass"
|
||||
message="All tests passed"
|
||||
else
|
||||
status="fail"
|
||||
message="Tests failing"
|
||||
OVERALL_STATUS="fail"
|
||||
fi
|
||||
elif [[ -f "pytest.ini" ]] || [[ -f "setup.py" ]]; then
|
||||
if python -m pytest &>/dev/null; then
|
||||
status="pass"
|
||||
message="All tests passed"
|
||||
else
|
||||
status="fail"
|
||||
message="Tests failing"
|
||||
OVERALL_STATUS="fail"
|
||||
fi
|
||||
elif [[ -f "Cargo.toml" ]]; then
|
||||
if cargo test &>/dev/null; then
|
||||
status="pass"
|
||||
message="All tests passed"
|
||||
else
|
||||
status="fail"
|
||||
message="Tests failing"
|
||||
OVERALL_STATUS="fail"
|
||||
fi
|
||||
elif [[ -f "go.mod" ]]; then
|
||||
if go test ./... &>/dev/null; then
|
||||
status="pass"
|
||||
message="All tests passed"
|
||||
else
|
||||
status="fail"
|
||||
message="Tests failing"
|
||||
OVERALL_STATUS="fail"
|
||||
fi
|
||||
else
|
||||
status="skip"
|
||||
message="No test framework detected"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "{\"status\": \"$status\", \"message\": \"$message\"}"
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Check if lint passes
|
||||
################################################################################
|
||||
check_lint() {
|
||||
local status="skip"
|
||||
local message="Linting skipped in quick mode"
|
||||
|
||||
if [[ "$QUICK_MODE" != "true" ]]; then
|
||||
# Detect linter and run
|
||||
if [[ -f "package.json" ]] && (grep -q "eslint" package.json || [[ -f ".eslintrc.json" ]]); then
|
||||
if npx eslint . --max-warnings 0 &>/dev/null; then
|
||||
status="pass"
|
||||
message="Linting passed"
|
||||
else
|
||||
status="fail"
|
||||
message="Linting errors found"
|
||||
OVERALL_STATUS="fail"
|
||||
fi
|
||||
elif command -v pylint &>/dev/null; then
|
||||
if pylint $(git diff --cached --name-only --diff-filter=ACM | grep '\.py$') &>/dev/null; then
|
||||
status="pass"
|
||||
message="Linting passed"
|
||||
else
|
||||
status="fail"
|
||||
message="Linting errors found"
|
||||
OVERALL_STATUS="fail"
|
||||
fi
|
||||
elif command -v clippy &>/dev/null; then
|
||||
if cargo clippy -- -D warnings &>/dev/null; then
|
||||
status="pass"
|
||||
message="Linting passed"
|
||||
else
|
||||
status="fail"
|
||||
message="Linting errors found"
|
||||
OVERALL_STATUS="fail"
|
||||
fi
|
||||
else
|
||||
status="skip"
|
||||
message="No linter detected"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "{\"status\": \"$status\", \"message\": \"$message\"}"
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Check for debug code in staged files
|
||||
################################################################################
|
||||
check_debug_code() {
|
||||
local count=0
|
||||
local locations=()
|
||||
|
||||
# Get staged diff
|
||||
local diff_output
|
||||
diff_output=$(git diff --cached)
|
||||
|
||||
# Search for debug patterns in added lines only
|
||||
local debug_patterns=(
|
||||
'console\.log'
|
||||
'console\.debug'
|
||||
'console\.error'
|
||||
'debugger'
|
||||
'print\('
|
||||
'println!'
|
||||
'pdb\.set_trace'
|
||||
'binding\.pry'
|
||||
'byebug'
|
||||
'Debug\.Log'
|
||||
)
|
||||
|
||||
for pattern in "${debug_patterns[@]}"; do
|
||||
while IFS= read -r line; do
|
||||
if [[ -n "$line" ]]; then
|
||||
((count++))
|
||||
locations+=("\"$line\"")
|
||||
fi
|
||||
done < <(echo "$diff_output" | grep "^+" | grep -v "^+++" | grep -E "$pattern" || true)
|
||||
done
|
||||
|
||||
local status="pass"
|
||||
local message="No debug code found"
|
||||
|
||||
if [[ $count -gt 0 ]]; then
|
||||
status="fail"
|
||||
message="Found $count debug statement(s)"
|
||||
OVERALL_STATUS="fail"
|
||||
fi
|
||||
|
||||
# Format locations array
|
||||
local locations_json="[]"
|
||||
if [[ ${#locations[@]} -gt 0 ]]; then
|
||||
locations_json="[$(IFS=,; echo "${locations[*]}")]"
|
||||
fi
|
||||
|
||||
echo "{\"status\": \"$status\", \"message\": \"$message\", \"count\": $count, \"locations\": $locations_json}"
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Check for TODOs in staged files
|
||||
################################################################################
|
||||
check_todos() {
|
||||
local count=0
|
||||
local locations=()
|
||||
|
||||
# Get staged diff
|
||||
local diff_output
|
||||
diff_output=$(git diff --cached)
|
||||
|
||||
# Search for TODO patterns in added lines only
|
||||
local todo_patterns=(
|
||||
'TODO'
|
||||
'FIXME'
|
||||
'XXX'
|
||||
'HACK'
|
||||
)
|
||||
|
||||
for pattern in "${todo_patterns[@]}"; do
|
||||
while IFS= read -r line; do
|
||||
if [[ -n "$line" ]]; then
|
||||
((count++))
|
||||
locations+=("\"$line\"")
|
||||
fi
|
||||
done < <(echo "$diff_output" | grep "^+" | grep -v "^+++" | grep -E "$pattern" || true)
|
||||
done
|
||||
|
||||
local status="pass"
|
||||
local message="No TODOs in staged code"
|
||||
|
||||
if [[ $count -gt 0 ]]; then
|
||||
status="warn"
|
||||
message="Found $count TODO/FIXME comment(s)"
|
||||
# TODOs are warning, not failure (project decision)
|
||||
fi
|
||||
|
||||
# Format locations array
|
||||
local locations_json="[]"
|
||||
if [[ ${#locations[@]} -gt 0 ]]; then
|
||||
locations_json="[$(IFS=,; echo "${locations[*]}")]"
|
||||
fi
|
||||
|
||||
echo "{\"status\": \"$status\", \"message\": \"$message\", \"count\": $count, \"locations\": $locations_json}"
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Check for merge conflict markers
|
||||
################################################################################
|
||||
check_merge_markers() {
|
||||
local count=0
|
||||
local locations=()
|
||||
|
||||
# Get staged files
|
||||
local staged_files
|
||||
staged_files=$(git diff --cached --name-only --diff-filter=ACM || true)
|
||||
|
||||
if [[ -n "$staged_files" ]]; then
|
||||
# Search for conflict markers in staged files
|
||||
while IFS= read -r file; do
|
||||
if [[ -f "$file" ]]; then
|
||||
local markers
|
||||
markers=$(grep -n -E '^(<<<<<<<|=======|>>>>>>>)' "$file" || true)
|
||||
if [[ -n "$markers" ]]; then
|
||||
while IFS= read -r marker; do
|
||||
((count++))
|
||||
locations+=("\"$file:$marker\"")
|
||||
done <<< "$markers"
|
||||
fi
|
||||
fi
|
||||
done <<< "$staged_files"
|
||||
fi
|
||||
|
||||
local status="pass"
|
||||
local message="No merge markers found"
|
||||
|
||||
if [[ $count -gt 0 ]]; then
|
||||
status="fail"
|
||||
message="Found $count merge conflict marker(s)"
|
||||
OVERALL_STATUS="fail"
|
||||
fi
|
||||
|
||||
# Format locations array
|
||||
local locations_json="[]"
|
||||
if [[ ${#locations[@]} -gt 0 ]]; then
|
||||
locations_json="[$(IFS=,; echo "${locations[*]}")]"
|
||||
fi
|
||||
|
||||
echo "{\"status\": \"$status\", \"message\": \"$message\", \"count\": $count, \"locations\": $locations_json}"
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Main execution
|
||||
################################################################################
|
||||
main() {
|
||||
# Verify we're in a git repository
|
||||
if ! git rev-parse --git-dir &>/dev/null; then
|
||||
echo "{\"error\": \"Not a git repository\"}"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Check if there are staged changes
|
||||
if ! git diff --cached --quiet 2>/dev/null; then
|
||||
: # Has staged changes, continue
|
||||
else
|
||||
echo "{\"error\": \"No staged changes to validate\"}"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Run all checks
|
||||
local tests_result
|
||||
local lint_result
|
||||
local debug_result
|
||||
local todos_result
|
||||
local markers_result
|
||||
|
||||
tests_result=$(check_tests)
|
||||
lint_result=$(check_lint)
|
||||
debug_result=$(check_debug_code)
|
||||
todos_result=$(check_todos)
|
||||
markers_result=$(check_merge_markers)
|
||||
|
||||
# Build JSON output
|
||||
cat <<EOF
|
||||
{
|
||||
"status": "$OVERALL_STATUS",
|
||||
"quick_mode": $([[ "$QUICK_MODE" == "true" ]] && echo "true" || echo "false"),
|
||||
"checks": {
|
||||
"tests": $tests_result,
|
||||
"lint": $lint_result,
|
||||
"debug_code": $debug_result,
|
||||
"todos": $todos_result,
|
||||
"merge_markers": $markers_result
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Exit with appropriate code
|
||||
if [[ "$OVERALL_STATUS" == "fail" ]]; then
|
||||
exit 1
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Execute main function
|
||||
main "$@"
|
||||
259
commands/commit-best-practices/.scripts/revert-helper.sh
Executable file
259
commands/commit-best-practices/.scripts/revert-helper.sh
Executable file
@@ -0,0 +1,259 @@
|
||||
#!/usr/bin/env bash
|
||||
################################################################################
|
||||
# Revert Helper Script
|
||||
#
|
||||
# Purpose: Generate proper revert commit message and analyze safety
|
||||
# Version: 1.0.0
|
||||
# Usage: ./revert-helper.sh <commit-sha>
|
||||
# Returns: JSON with revert information
|
||||
# Exit Codes:
|
||||
# 0 = Success
|
||||
# 1 = Commit not found
|
||||
# 2 = Script execution error
|
||||
################################################################################
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
################################################################################
|
||||
# Parse conventional commit message
|
||||
################################################################################
|
||||
parse_commit_message() {
|
||||
local subject="$1"
|
||||
|
||||
local type=""
|
||||
local scope=""
|
||||
local description=""
|
||||
|
||||
# Try to match conventional format: type(scope): description
|
||||
if [[ "$subject" =~ ^([a-z]+)(\([a-z0-9\-]+\)):[[:space:]](.+)$ ]]; then
|
||||
type="${BASH_REMATCH[1]}"
|
||||
scope="${BASH_REMATCH[2]}" # includes parentheses
|
||||
scope="${scope#(}" # remove leading (
|
||||
scope="${scope%)}" # remove trailing )
|
||||
description="${BASH_REMATCH[3]}"
|
||||
# Try to match without scope: type: description
|
||||
elif [[ "$subject" =~ ^([a-z]+):[[:space:]](.+)$ ]]; then
|
||||
type="${BASH_REMATCH[1]}"
|
||||
scope=""
|
||||
description="${BASH_REMATCH[2]}"
|
||||
else
|
||||
# Non-conventional format
|
||||
type=""
|
||||
scope=""
|
||||
description="$subject"
|
||||
fi
|
||||
|
||||
echo "$type|$scope|$description"
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Generate revert commit message
|
||||
################################################################################
|
||||
generate_revert_message() {
|
||||
local commit_sha="$1"
|
||||
local original_subject="$2"
|
||||
|
||||
# Parse original message
|
||||
local parsed
|
||||
parsed=$(parse_commit_message "$original_subject")
|
||||
|
||||
local type
|
||||
local scope
|
||||
local description
|
||||
|
||||
IFS='|' read -r type scope description <<< "$parsed"
|
||||
|
||||
# Build revert message
|
||||
local revert_subject
|
||||
if [[ -n "$type" ]]; then
|
||||
# Conventional format
|
||||
if [[ -n "$scope" ]]; then
|
||||
revert_subject="revert: $type($scope): $description"
|
||||
else
|
||||
revert_subject="revert: $type: $description"
|
||||
fi
|
||||
else
|
||||
# Non-conventional format
|
||||
revert_subject="revert: $original_subject"
|
||||
fi
|
||||
|
||||
# Build full message (subject + body + footer)
|
||||
local revert_message
|
||||
revert_message=$(cat <<EOF
|
||||
$revert_subject
|
||||
|
||||
This reverts commit $commit_sha.
|
||||
|
||||
Reason: [Provide reason for revert here]
|
||||
EOF
|
||||
)
|
||||
|
||||
echo "$revert_message"
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Analyze revert safety
|
||||
################################################################################
|
||||
analyze_revert_safety() {
|
||||
local commit_sha="$1"
|
||||
|
||||
local safe_to_revert="true"
|
||||
local warnings=()
|
||||
|
||||
# Check for dependent commits (commits that touch same files after this one)
|
||||
local files_changed
|
||||
files_changed=$(git show --name-only --format= "$commit_sha")
|
||||
|
||||
local dependent_count=0
|
||||
local dependent_commits=()
|
||||
|
||||
if [[ -n "$files_changed" ]]; then
|
||||
# Get commits after this one
|
||||
local later_commits
|
||||
later_commits=$(git log "$commit_sha"..HEAD --oneline --format='%h %s' || echo "")
|
||||
|
||||
if [[ -n "$later_commits" ]]; then
|
||||
while IFS= read -r commit_line; do
|
||||
local later_sha
|
||||
later_sha=$(echo "$commit_line" | awk '{print $1}')
|
||||
|
||||
# Check if any files overlap
|
||||
local later_files
|
||||
later_files=$(git show --name-only --format= "$later_sha" 2>/dev/null || echo "")
|
||||
|
||||
# Check for file overlap
|
||||
while IFS= read -r file; do
|
||||
if [[ -n "$file" ]] && echo "$files_changed" | grep -qxF "$file"; then
|
||||
dependent_commits+=("$commit_line")
|
||||
((dependent_count++))
|
||||
break
|
||||
fi
|
||||
done <<< "$later_files"
|
||||
done <<< "$later_commits"
|
||||
|
||||
if [[ $dependent_count -gt 0 ]]; then
|
||||
safe_to_revert="false"
|
||||
warnings+=("\"$dependent_count commit(s) depend on this change\"")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if files still exist (if deleted, might be harder to revert)
|
||||
local deleted_files=0
|
||||
while IFS= read -r file; do
|
||||
if [[ -n "$file" ]] && [[ ! -f "$file" ]]; then
|
||||
((deleted_files++))
|
||||
fi
|
||||
done <<< "$files_changed"
|
||||
|
||||
if [[ $deleted_files -gt 0 ]]; then
|
||||
warnings+=("\"$deleted_files file(s) from commit no longer exist\"")
|
||||
fi
|
||||
|
||||
# Check for potential merge conflicts (files modified since commit)
|
||||
local modified_files=0
|
||||
while IFS= read -r file; do
|
||||
if [[ -n "$file" ]] && [[ -f "$file" ]]; then
|
||||
# Check if file has been modified since this commit
|
||||
local file_changed
|
||||
file_changed=$(git log "$commit_sha"..HEAD --oneline -- "$file" | wc -l)
|
||||
if [[ $file_changed -gt 0 ]]; then
|
||||
((modified_files++))
|
||||
fi
|
||||
fi
|
||||
done <<< "$files_changed"
|
||||
|
||||
if [[ $modified_files -gt 0 ]]; then
|
||||
warnings+=("\"$modified_files file(s) modified since commit - potential conflicts\"")
|
||||
fi
|
||||
|
||||
# Format warnings array
|
||||
local warnings_json="[]"
|
||||
if [[ ${#warnings[@]} -gt 0 ]]; then
|
||||
warnings_json="[$(IFS=,; echo "${warnings[*]}")]"
|
||||
fi
|
||||
|
||||
echo "{\"safe_to_revert\": $safe_to_revert, \"warnings\": $warnings_json, \"dependent_count\": $dependent_count}"
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Main execution
|
||||
################################################################################
|
||||
main() {
|
||||
# Check arguments
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "{\"error\": \"Usage: revert-helper.sh <commit-sha>\"}"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
local commit_sha="$1"
|
||||
|
||||
# Verify we're in a git repository
|
||||
if ! git rev-parse --git-dir &>/dev/null; then
|
||||
echo "{\"error\": \"Not a git repository\"}"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Verify commit exists
|
||||
if ! git rev-parse --verify "$commit_sha" &>/dev/null 2>&1; then
|
||||
echo "{\"error\": \"Commit not found: $commit_sha\"}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get full commit SHA
|
||||
local full_sha
|
||||
full_sha=$(git rev-parse "$commit_sha")
|
||||
|
||||
local short_sha
|
||||
short_sha=$(git rev-parse --short "$commit_sha")
|
||||
|
||||
# Get commit information
|
||||
local original_subject
|
||||
local original_author
|
||||
local commit_date
|
||||
local files_affected
|
||||
|
||||
original_subject=$(git log -1 --format='%s' "$commit_sha")
|
||||
original_author=$(git log -1 --format='%an <%ae>' "$commit_sha")
|
||||
commit_date=$(git log -1 --format='%ad' --date=short "$commit_sha")
|
||||
files_affected=$(git show --name-only --format= "$commit_sha" | wc -l)
|
||||
|
||||
# Parse commit type and scope
|
||||
local parsed
|
||||
parsed=$(parse_commit_message "$original_subject")
|
||||
|
||||
local type
|
||||
local scope
|
||||
local description
|
||||
|
||||
IFS='|' read -r type scope description <<< "$parsed"
|
||||
|
||||
# Generate revert message
|
||||
local revert_message
|
||||
revert_message=$(generate_revert_message "$short_sha" "$original_subject")
|
||||
|
||||
# Analyze safety
|
||||
local safety_analysis
|
||||
safety_analysis=$(analyze_revert_safety "$commit_sha")
|
||||
|
||||
# Build JSON output
|
||||
cat <<EOF
|
||||
{
|
||||
"commit": "$short_sha",
|
||||
"full_sha": "$full_sha",
|
||||
"original_message": "$original_subject",
|
||||
"original_author": "$original_author",
|
||||
"commit_date": "$commit_date",
|
||||
"type": ${type:+\"$type\"},
|
||||
"scope": ${scope:+\"$scope\"},
|
||||
"files_affected": $files_affected,
|
||||
"revert_message": $(echo "$revert_message" | jq -Rs .),
|
||||
"safety": $safety_analysis
|
||||
}
|
||||
EOF
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Execute main function
|
||||
main "$@"
|
||||
255
commands/commit-best-practices/USAGE_EXAMPLES.md
Normal file
255
commands/commit-best-practices/USAGE_EXAMPLES.md
Normal file
@@ -0,0 +1,255 @@
|
||||
# Commit Best Practices Skill - Usage Examples
|
||||
|
||||
## Quick Reference
|
||||
|
||||
```bash
|
||||
# Pre-commit validation (full)
|
||||
/commit-best-practices check-pre-commit
|
||||
|
||||
# Pre-commit validation (quick - skip tests/lint)
|
||||
/commit-best-practices check-pre-commit quick:true
|
||||
|
||||
# Review last commit
|
||||
/commit-best-practices review-commit
|
||||
|
||||
# Review specific commit
|
||||
/commit-best-practices review-commit commit:abc123
|
||||
|
||||
# Check if safe to amend
|
||||
/commit-best-practices amend-guidance
|
||||
|
||||
# Amend with force (bypass safety)
|
||||
/commit-best-practices amend-guidance force:true
|
||||
|
||||
# Revert guidance for commit
|
||||
/commit-best-practices revert-guidance commit:abc123
|
||||
|
||||
# Workflow tips (all)
|
||||
/commit-best-practices workflow-tips
|
||||
|
||||
# Workflow tips (specific focus)
|
||||
/commit-best-practices workflow-tips focus:commit
|
||||
/commit-best-practices workflow-tips focus:branch
|
||||
/commit-best-practices workflow-tips focus:merge
|
||||
```
|
||||
|
||||
## Workflow Example 1: Safe Commit Flow
|
||||
|
||||
```
|
||||
Developer: "I want to commit my changes"
|
||||
|
||||
Agent:
|
||||
1. Runs: /commit-best-practices check-pre-commit
|
||||
2. IF checks fail:
|
||||
- Shows: "Tests failing, debug code found"
|
||||
- Blocks commit
|
||||
- Provides guidance to fix
|
||||
3. IF checks pass:
|
||||
- Continues with commit workflow
|
||||
- Generates message
|
||||
- Creates commit
|
||||
- Reviews commit quality
|
||||
```
|
||||
|
||||
## Workflow Example 2: Amend Safety Check
|
||||
|
||||
```
|
||||
Developer: "I need to amend my last commit"
|
||||
|
||||
Agent:
|
||||
1. Runs: /commit-best-practices amend-guidance
|
||||
2. Checks:
|
||||
- Not pushed to remote? ✓
|
||||
- Same author? ✓
|
||||
- Not on main/master? ✓
|
||||
3. Result: SAFE - provides amend instructions
|
||||
|
||||
OR if unsafe:
|
||||
|
||||
3. Result: UNSAFE - commit already pushed
|
||||
- Shows alternatives (new commit, revert)
|
||||
- Blocks amend
|
||||
```
|
||||
|
||||
## Workflow Example 3: Commit Review & Improvement
|
||||
|
||||
```
|
||||
Developer commits code
|
||||
|
||||
Agent (automatically):
|
||||
1. Runs: /commit-best-practices review-commit
|
||||
2. Analyzes:
|
||||
- Message quality: GOOD
|
||||
- Atomicity: ✓ single feature
|
||||
- Tests: ⚠ missing
|
||||
- Score: 72/100
|
||||
3. Suggests:
|
||||
- "Good commit! Consider adding unit tests."
|
||||
- "Safe to push with minor note."
|
||||
```
|
||||
|
||||
## Script Output Examples
|
||||
|
||||
### pre-commit-check.sh
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "fail",
|
||||
"quick_mode": false,
|
||||
"checks": {
|
||||
"tests": {"status": "fail", "message": "Tests failing"},
|
||||
"lint": {"status": "pass", "message": "Linting passed"},
|
||||
"debug_code": {"status": "fail", "count": 3, "locations": ["src/auth.js:42: console.log(user)"]},
|
||||
"todos": {"status": "warn", "count": 1, "locations": ["src/auth.js:56: TODO: refactor"]},
|
||||
"merge_markers": {"status": "pass", "count": 0, "locations": []}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### commit-reviewer.py
|
||||
|
||||
```json
|
||||
{
|
||||
"commit": "abc123",
|
||||
"author": "John Doe <john@example.com>",
|
||||
"date": "2025-10-13",
|
||||
"message": {
|
||||
"subject": "feat(auth): add OAuth authentication",
|
||||
"subject_length": 38,
|
||||
"conventional": true,
|
||||
"type": "feat",
|
||||
"scope": "auth"
|
||||
},
|
||||
"changes": {
|
||||
"files_changed": 5,
|
||||
"insertions": 234,
|
||||
"deletions": 12,
|
||||
"test_files": 1
|
||||
},
|
||||
"quality": {
|
||||
"atomic": true,
|
||||
"message_quality": "excellent",
|
||||
"test_coverage": true,
|
||||
"issues": []
|
||||
},
|
||||
"score": 95
|
||||
}
|
||||
```
|
||||
|
||||
### amend-safety.sh
|
||||
|
||||
```json
|
||||
{
|
||||
"safe": true,
|
||||
"recommendation": "safe",
|
||||
"commit": "abc123",
|
||||
"author": "John Doe <john@example.com>",
|
||||
"branch": "feature/oauth",
|
||||
"checks": {
|
||||
"not_pushed": {"status": "pass", "message": "Commit not pushed to origin/feature/oauth"},
|
||||
"same_author": {"status": "pass", "message": "You are the commit author"},
|
||||
"safe_branch": {"status": "pass", "message": "On feature branch: feature/oauth"},
|
||||
"collaborators": {"status": "pass", "message": "Solo work on branch"}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### revert-helper.sh
|
||||
|
||||
```json
|
||||
{
|
||||
"commit": "abc123",
|
||||
"original_message": "feat(auth): add OAuth authentication",
|
||||
"type": "feat",
|
||||
"scope": "auth",
|
||||
"files_affected": 5,
|
||||
"revert_message": "revert: feat(auth): add OAuth authentication\n\nThis reverts commit abc123.\n\nReason: [Provide reason here]",
|
||||
"safety": {
|
||||
"safe_to_revert": true,
|
||||
"warnings": [],
|
||||
"dependent_count": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Integration with Other Skills
|
||||
|
||||
```
|
||||
/commit-best-practices check-pre-commit
|
||||
↓ (if pass)
|
||||
/commit-analysis analyze
|
||||
↓
|
||||
/message-generation complete-message
|
||||
↓
|
||||
/commit (create commit)
|
||||
↓
|
||||
/commit-best-practices review-commit
|
||||
↓ (if score < 70)
|
||||
/commit-best-practices amend-guidance
|
||||
```
|
||||
|
||||
## Best Practices Enforced
|
||||
|
||||
1. **Tests must pass** - No commits with failing tests
|
||||
2. **No debug code** - No console.log, debugger in commits
|
||||
3. **No TODOs** - Fix or remove before committing
|
||||
4. **No merge markers** - Resolve conflicts fully
|
||||
5. **Atomic commits** - One logical change per commit
|
||||
6. **Quality messages** - Conventional commits format
|
||||
7. **Safe amends** - Only amend unpushed commits
|
||||
8. **Proper reverts** - Use revert for shared history
|
||||
|
||||
## Common Scenarios
|
||||
|
||||
### Scenario 1: Debug Code Found
|
||||
|
||||
```
|
||||
Pre-commit check fails:
|
||||
❌ Debug code: 3 instances found
|
||||
- src/auth.js:42: console.log(user)
|
||||
- src/api.js:18: debugger statement
|
||||
|
||||
Action: Remove debug code, re-stage files, retry
|
||||
```
|
||||
|
||||
### Scenario 2: Tests Failing
|
||||
|
||||
```
|
||||
Pre-commit check fails:
|
||||
❌ Tests: 2 failing
|
||||
- test/auth.test.js: OAuth flow test
|
||||
|
||||
Action: Fix tests, verify passing, retry
|
||||
```
|
||||
|
||||
### Scenario 3: Unsafe Amend
|
||||
|
||||
```
|
||||
Amend safety check:
|
||||
❌ UNSAFE: Commit already pushed to remote
|
||||
|
||||
Alternatives:
|
||||
1. Create new commit (recommended)
|
||||
2. Use git revert (if undoing)
|
||||
3. Coordinate with team before force push
|
||||
```
|
||||
|
||||
### Scenario 4: Non-Atomic Commit
|
||||
|
||||
```
|
||||
Commit review:
|
||||
Score: 58/100
|
||||
⚠ Non-atomic: Mixes feat + fix + docs
|
||||
|
||||
Recommendation:
|
||||
Split into 3 commits:
|
||||
1. feat(auth): OAuth implementation
|
||||
2. fix(api): null pointer handling
|
||||
3. docs: authentication guide
|
||||
|
||||
Use: /commit-split
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
This skill ensures high-quality commits through automated validation, intelligent review, and guided workflows.
|
||||
373
commands/commit-best-practices/amend-guidance.md
Normal file
373
commands/commit-best-practices/amend-guidance.md
Normal file
@@ -0,0 +1,373 @@
|
||||
# Operation: Safe Commit Amend Guidance
|
||||
|
||||
Guide users through safely amending commits with comprehensive safety checks.
|
||||
|
||||
## Parameters from $ARGUMENTS
|
||||
|
||||
- **force** (optional): Skip safety checks (default: false) - USE WITH EXTREME CAUTION
|
||||
|
||||
Parse as: `amend-guidance force:true` or `amend-guidance`
|
||||
|
||||
## Amend Safety Workflow
|
||||
|
||||
### Step 1: Run Amend Safety Check
|
||||
|
||||
Execute safety validation script:
|
||||
|
||||
```bash
|
||||
./.claude/commands/commit-best-practices/.scripts/amend-safety.sh
|
||||
```
|
||||
|
||||
The script checks:
|
||||
1. Commit not pushed to remote
|
||||
2. Same author (current user matches commit author)
|
||||
3. Not on protected branch (main/master)
|
||||
4. No collaborators have pulled it
|
||||
|
||||
Returns:
|
||||
```json
|
||||
{
|
||||
"safe": true|false,
|
||||
"checks": {
|
||||
"not_pushed": {"status": "pass|fail", "message": "..."},
|
||||
"same_author": {"status": "pass|fail", "message": "..."},
|
||||
"safe_branch": {"status": "pass|warn", "message": "..."},
|
||||
"collaborators": {"status": "pass|warn", "message": "..."}
|
||||
},
|
||||
"recommendation": "safe|warning|unsafe"
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Evaluate Safety Status
|
||||
|
||||
**SAFE (All checks pass):**
|
||||
```
|
||||
✅ SAFE TO AMEND
|
||||
|
||||
Last commit: abc123
|
||||
Author: John Doe <john@example.com> (you)
|
||||
Branch: feature/oauth-implementation
|
||||
Status: Not pushed to remote
|
||||
|
||||
All safety checks passed:
|
||||
✅ Commit not pushed to remote
|
||||
✅ You are the author
|
||||
✅ Not on main/master branch
|
||||
✅ No collaborators have this commit
|
||||
|
||||
It is SAFE to amend this commit.
|
||||
```
|
||||
|
||||
**WARNING (Minor concerns):**
|
||||
```
|
||||
⚠️ AMEND WITH CAUTION
|
||||
|
||||
Last commit: abc123
|
||||
Author: John Doe <john@example.com> (you)
|
||||
Branch: main
|
||||
Status: Not pushed to remote
|
||||
|
||||
Safety checks:
|
||||
✅ Commit not pushed to remote
|
||||
✅ You are the author
|
||||
⚠️ WARNING: On main/master branch
|
||||
✅ No collaborators have this commit
|
||||
|
||||
Amending on main/master is discouraged but technically safe if not pushed.
|
||||
|
||||
Recommendation: Create new commit instead of amending.
|
||||
```
|
||||
|
||||
**UNSAFE (Critical issues):**
|
||||
```
|
||||
❌ UNSAFE TO AMEND
|
||||
|
||||
Last commit: abc123
|
||||
Author: Jane Smith <jane@example.com> (NOT you)
|
||||
Branch: feature/oauth
|
||||
Status: Pushed to origin/feature/oauth
|
||||
|
||||
Safety violations:
|
||||
❌ CRITICAL: Commit already pushed to remote
|
||||
❌ CRITICAL: Different author (Jane Smith, not you)
|
||||
✅ Safe branch (not main/master)
|
||||
⚠️ WARNING: Other developers may have pulled this
|
||||
|
||||
DO NOT AMEND THIS COMMIT!
|
||||
|
||||
Amending will:
|
||||
1. Rewrite git history
|
||||
2. Break other developers' work
|
||||
3. Require force push (dangerous)
|
||||
4. Cause merge conflicts for collaborators
|
||||
|
||||
Use: git revert (to undo changes safely)
|
||||
Or: Create new commit (to add fixes)
|
||||
```
|
||||
|
||||
### Step 3: Provide Amend Instructions
|
||||
|
||||
**If SAFE, show how to amend:**
|
||||
|
||||
```
|
||||
How to Amend Commit
|
||||
===================
|
||||
|
||||
Current commit message:
|
||||
---
|
||||
feat(auth): add OAuth authentication
|
||||
|
||||
Implement OAuth2 flow for Google and GitHub
|
||||
---
|
||||
|
||||
Option 1: Amend with staged changes
|
||||
-------------------------------------
|
||||
1. Make your changes to files
|
||||
2. Stage changes: git add <files>
|
||||
3. Amend commit: git commit --amend
|
||||
|
||||
This opens editor to modify message if needed.
|
||||
|
||||
Option 2: Amend message only
|
||||
-----------------------------
|
||||
git commit --amend
|
||||
|
||||
Opens editor to change commit message.
|
||||
No file changes included.
|
||||
|
||||
Option 3: Amend with new message (no editor)
|
||||
---------------------------------------------
|
||||
git commit --amend -m "new message here"
|
||||
|
||||
Direct message change without editor.
|
||||
|
||||
After amending:
|
||||
---------------
|
||||
Review commit: /commit-best-practices review-commit
|
||||
Verify changes: git show HEAD
|
||||
Continue work or push: git push origin <branch>
|
||||
|
||||
Note: If you already pushed, you'll need: git push --force-with-lease
|
||||
(Only if you're certain no one else has pulled your changes!)
|
||||
```
|
||||
|
||||
**If UNSAFE, show alternatives:**
|
||||
|
||||
```
|
||||
Safe Alternatives to Amending
|
||||
==============================
|
||||
|
||||
Since amending is unsafe, use these alternatives:
|
||||
|
||||
Option 1: Create New Commit (Recommended)
|
||||
------------------------------------------
|
||||
Make your changes and commit normally:
|
||||
|
||||
1. Make changes to files
|
||||
2. Stage: git add <files>
|
||||
3. Commit: git commit -m "fix: address review feedback"
|
||||
|
||||
This preserves history and is safe for collaborators.
|
||||
|
||||
Option 2: Revert Previous Commit
|
||||
---------------------------------
|
||||
If the commit is wrong, revert it:
|
||||
|
||||
1. Revert: git revert HEAD
|
||||
2. Make correct changes
|
||||
3. Commit: git commit -m "correct implementation"
|
||||
|
||||
This creates two new commits (revert + fix).
|
||||
|
||||
Option 3: Interactive Rebase (Advanced)
|
||||
----------------------------------------
|
||||
Only if you're experienced and coordinate with team:
|
||||
|
||||
1. git rebase -i HEAD~2
|
||||
2. Mark commit as 'edit'
|
||||
3. Make changes
|
||||
4. git rebase --continue
|
||||
|
||||
⚠️ WARNING: Requires force push, coordinate with team!
|
||||
|
||||
Best Practice:
|
||||
--------------
|
||||
When in doubt, create a new commit. It's always safer.
|
||||
```
|
||||
|
||||
### Step 4: Force Mode Handling
|
||||
|
||||
If user specified `force:true`:
|
||||
|
||||
```
|
||||
⚠️ FORCE MODE ENABLED
|
||||
|
||||
You've bypassed safety checks. This is DANGEROUS!
|
||||
|
||||
Proceeding with amend despite warnings.
|
||||
|
||||
Current commit: abc123
|
||||
Branch: main
|
||||
Status: Pushed to remote
|
||||
|
||||
You are responsible for:
|
||||
1. Coordinating with team before force push
|
||||
2. Ensuring no one has pulled this commit
|
||||
3. Handling any conflicts that arise
|
||||
4. Notifying team of force push
|
||||
|
||||
Force push command (if you must):
|
||||
git push --force-with-lease origin <branch>
|
||||
|
||||
Better alternatives:
|
||||
- Create new commit instead
|
||||
- Use git revert for pushed commits
|
||||
- Coordinate with team before rewriting history
|
||||
|
||||
Proceed with extreme caution!
|
||||
```
|
||||
|
||||
## Safety Rules Summary
|
||||
|
||||
### ✅ SAFE to amend if ALL true:
|
||||
|
||||
1. **Not pushed to remote**
|
||||
- `git log @{upstream}..HEAD` shows commit
|
||||
- Commit only exists locally
|
||||
|
||||
2. **Same author**
|
||||
- `git config user.email` matches commit author
|
||||
- You made the commit
|
||||
|
||||
3. **Not on protected branch**
|
||||
- Not on main/master
|
||||
- Or: on feature branch
|
||||
|
||||
4. **No collaborators affected**
|
||||
- Solo work on branch
|
||||
- Or: coordinated with team
|
||||
|
||||
### ❌ NEVER amend if ANY true:
|
||||
|
||||
1. **Already pushed to remote**
|
||||
- Commit exists on origin
|
||||
- Others may have pulled it
|
||||
|
||||
2. **Different author**
|
||||
- Someone else made the commit
|
||||
- Not your work to modify
|
||||
|
||||
3. **Collaborators working on same branch**
|
||||
- Team has pulled your commit
|
||||
- Would break their work
|
||||
|
||||
4. **On shared/protected branch**
|
||||
- main/master branch
|
||||
- Production/release branches
|
||||
|
||||
## When Amend is Useful
|
||||
|
||||
**Good use cases:**
|
||||
- Fix typo in commit message (before push)
|
||||
- Add forgotten file to commit (before push)
|
||||
- Improve commit message clarity (before push)
|
||||
- Reformat message to match conventions (before push)
|
||||
|
||||
**Bad use cases:**
|
||||
- Fixing bug in pushed commit (use new commit)
|
||||
- Changing commit after code review started (confusing)
|
||||
- Modifying shared branch commits (breaks collaboration)
|
||||
- Rewriting public history (dangerous)
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
Amend Safety Check
|
||||
==================
|
||||
|
||||
Commit: <sha>
|
||||
Author: <name> <email> [you|NOT you]
|
||||
Branch: <branch>
|
||||
Status: [Local only|Pushed to <remote>]
|
||||
|
||||
SAFETY CHECKS:
|
||||
[✅|⚠️|❌] Commit not pushed
|
||||
[✅|⚠️|❌] Same author
|
||||
[✅|⚠️|❌] Safe branch
|
||||
[✅|⚠️|❌] No collaborators affected
|
||||
|
||||
VERDICT: [SAFE|WARNING|UNSAFE]
|
||||
|
||||
[Detailed explanation]
|
||||
|
||||
[If SAFE: Amend instructions]
|
||||
[If UNSAFE: Safe alternatives]
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
**No commits to amend:**
|
||||
```
|
||||
ERROR: No commits to amend
|
||||
This is the first commit (no parent)
|
||||
Use: git commit (to create first commit)
|
||||
```
|
||||
|
||||
**Not a git repository:**
|
||||
```
|
||||
ERROR: Not a git repository
|
||||
Run: git init (to initialize)
|
||||
```
|
||||
|
||||
**Script execution error:**
|
||||
```
|
||||
ERROR: Amend safety check script failed
|
||||
Check: .claude/commands/commit-best-practices/.scripts/amend-safety.sh exists
|
||||
Verify: Script is executable
|
||||
```
|
||||
|
||||
## Integration with Agent
|
||||
|
||||
When user says "amend my commit" or "fix my commit":
|
||||
1. Agent MUST run safety check FIRST
|
||||
2. If unsafe, BLOCK amend and show alternatives
|
||||
3. If safe, provide clear amend instructions
|
||||
4. Never allow unsafe amend without explicit force flag
|
||||
|
||||
## Git Commands Reference
|
||||
|
||||
```bash
|
||||
# Check if commit is pushed
|
||||
git log @{upstream}..HEAD
|
||||
|
||||
# Check commit author
|
||||
git log -1 --format='%an %ae'
|
||||
|
||||
# Check current branch
|
||||
git branch --show-current
|
||||
|
||||
# Check remote tracking
|
||||
git rev-parse --abbrev-ref --symbolic-full-name @{upstream}
|
||||
|
||||
# Amend commit (opens editor)
|
||||
git commit --amend
|
||||
|
||||
# Amend with message (no editor)
|
||||
git commit --amend -m "new message"
|
||||
|
||||
# Amend without changing message
|
||||
git commit --amend --no-edit
|
||||
|
||||
# Force push if needed (DANGEROUS)
|
||||
git push --force-with-lease origin <branch>
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Default to safe**: Always check before amending
|
||||
2. **Never force without reason**: Force flag is dangerous
|
||||
3. **Prefer new commits**: When in doubt, commit new changes
|
||||
4. **Communicate**: Tell team before force pushing
|
||||
5. **Use revert**: For pushed commits, revert instead of amend
|
||||
|
||||
Safe git practices prevent broken collaboration and lost work.
|
||||
214
commands/commit-best-practices/check-pre-commit.md
Normal file
214
commands/commit-best-practices/check-pre-commit.md
Normal file
@@ -0,0 +1,214 @@
|
||||
# Operation: Pre-Commit Validation
|
||||
|
||||
Validate repository state and changes before committing to ensure quality standards.
|
||||
|
||||
## Parameters from $ARGUMENTS
|
||||
|
||||
- **quick** (optional): `true` for fast checks only, `false` for full validation (default: false)
|
||||
|
||||
Parse as: `check-pre-commit quick:true` or `check-pre-commit`
|
||||
|
||||
## Pre-Commit Validation Workflow
|
||||
|
||||
### Step 1: Repository State Check
|
||||
|
||||
Verify git repository is valid and has changes:
|
||||
|
||||
```bash
|
||||
# Check if git repository
|
||||
if ! git rev-parse --git-dir >/dev/null 2>&1; then
|
||||
ERROR: "Not a git repository"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for changes to commit
|
||||
git status --short
|
||||
```
|
||||
|
||||
If no changes, inform user: "Working tree clean. No changes to commit."
|
||||
|
||||
### Step 2: Run Pre-Commit Checks Script
|
||||
|
||||
Execute comprehensive validation:
|
||||
|
||||
```bash
|
||||
cd $(git rev-parse --show-toplevel)
|
||||
./.claude/commands/commit-best-practices/.scripts/pre-commit-check.sh quick:${quick:-false}
|
||||
```
|
||||
|
||||
The script returns JSON:
|
||||
```json
|
||||
{
|
||||
"status": "pass|fail",
|
||||
"checks": {
|
||||
"tests": {"status": "pass|fail|skip", "message": "..."},
|
||||
"lint": {"status": "pass|fail|skip", "message": "..."},
|
||||
"debug_code": {"status": "pass|fail", "count": 0, "locations": []},
|
||||
"todos": {"status": "pass|warn", "count": 0, "locations": []},
|
||||
"merge_markers": {"status": "pass|fail", "count": 0, "locations": []}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Parse Results
|
||||
|
||||
**If status = "pass"**:
|
||||
```
|
||||
✅ Pre-commit validation passed!
|
||||
|
||||
All checks completed successfully:
|
||||
✅ Tests: passed
|
||||
✅ Lint: passed
|
||||
✅ Debug code: none found
|
||||
✅ TODOs: none in committed code
|
||||
✅ Merge markers: none found
|
||||
|
||||
Safe to commit. Proceed with: /commit
|
||||
```
|
||||
|
||||
**If status = "fail"**:
|
||||
```
|
||||
❌ Pre-commit validation failed!
|
||||
|
||||
Issues found:
|
||||
❌ Tests: 2 failing
|
||||
- test/auth.test.js: OAuth flow test
|
||||
- test/api.test.js: null pointer test
|
||||
|
||||
❌ Debug code: 3 instances found
|
||||
- src/auth.js:42: console.log(user)
|
||||
- src/api.js:18: debugger statement
|
||||
- src/utils.js:91: print(response)
|
||||
|
||||
❌ TODOs: 1 found in staged code
|
||||
- src/auth.js:56: TODO: refactor this
|
||||
|
||||
Cannot commit until issues are resolved.
|
||||
|
||||
Actions to take:
|
||||
1. Fix failing tests
|
||||
2. Remove debug statements (console.log, debugger, print)
|
||||
3. Resolve or remove TODOs in staged files
|
||||
4. Run: /commit-best-practices check-pre-commit (to re-validate)
|
||||
```
|
||||
|
||||
### Step 4: Provide Guidance
|
||||
|
||||
Based on failures, provide specific remediation:
|
||||
|
||||
**Tests Failing:**
|
||||
```
|
||||
To fix tests:
|
||||
1. Run tests locally: npm test (or pytest, cargo test, etc.)
|
||||
2. Review failures and fix issues
|
||||
3. Verify all tests pass
|
||||
4. Re-run validation
|
||||
```
|
||||
|
||||
**Debug Code Found:**
|
||||
```
|
||||
To remove debug code:
|
||||
1. Search for: console.log, debugger, print(, pdb.
|
||||
2. Remove or comment out debug statements
|
||||
3. Consider using proper logging instead
|
||||
4. Re-stage files: git add <file>
|
||||
```
|
||||
|
||||
**TODOs in Committed Code:**
|
||||
```
|
||||
TODOs found in staged code:
|
||||
1. Either: Fix the TODO items now
|
||||
2. Or: Unstage files with TODOs (git reset HEAD <file>)
|
||||
3. Or: Remove TODO comments temporarily
|
||||
|
||||
Best practice: Don't commit TODOs to main/master
|
||||
```
|
||||
|
||||
**Merge Markers Found:**
|
||||
```
|
||||
Merge conflict markers detected:
|
||||
- <<<<<<<
|
||||
- =======
|
||||
- >>>>>>>
|
||||
|
||||
Actions:
|
||||
1. Resolve merge conflicts completely
|
||||
2. Remove all conflict markers
|
||||
3. Test merged code
|
||||
4. Re-stage resolved files
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
Provide clear, actionable feedback:
|
||||
|
||||
```
|
||||
Pre-Commit Validation Report
|
||||
============================
|
||||
|
||||
Status: [PASS|FAIL]
|
||||
|
||||
Checks Performed:
|
||||
[✅|❌] Tests: [result]
|
||||
[✅|❌] Lint: [result]
|
||||
[✅|❌] Debug Code: [result]
|
||||
[✅|❌] TODOs: [result]
|
||||
[✅|❌] Merge Markers: [result]
|
||||
|
||||
[If FAIL: Detailed issue list with file locations]
|
||||
|
||||
[If FAIL: Remediation steps]
|
||||
|
||||
[If PASS: "Safe to commit" confirmation]
|
||||
```
|
||||
|
||||
## Quick Mode
|
||||
|
||||
If `quick:true`:
|
||||
- Skip test execution (assume tests run in CI)
|
||||
- Skip lint execution (assume linter runs separately)
|
||||
- Only check: debug code, TODOs, merge markers
|
||||
- Much faster (~1 second vs ~30 seconds)
|
||||
|
||||
Use quick mode for rapid iteration during development.
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Not a git repository:**
|
||||
```
|
||||
ERROR: Not a git repository
|
||||
Run: git init (to initialize)
|
||||
Or: cd to correct directory
|
||||
```
|
||||
|
||||
**No changes to validate:**
|
||||
```
|
||||
INFO: Working tree clean
|
||||
No changes staged for commit
|
||||
Use: git add <files> (to stage changes)
|
||||
```
|
||||
|
||||
**Script execution error:**
|
||||
```
|
||||
ERROR: Pre-commit check script failed
|
||||
Check: .claude/commands/commit-best-practices/.scripts/pre-commit-check.sh exists
|
||||
Verify: Script is executable (chmod +x)
|
||||
```
|
||||
|
||||
## Integration with Agent
|
||||
|
||||
When user says "commit my changes":
|
||||
1. Agent MUST run this check FIRST
|
||||
2. If check fails, BLOCK commit and provide guidance
|
||||
3. If check passes, proceed with commit workflow
|
||||
4. Never allow commit with failing validation (unless user explicitly forces)
|
||||
|
||||
## Best Practices Enforced
|
||||
|
||||
1. **Tests must pass** - Failing tests = broken code
|
||||
2. **No debug code** - console.log, debugger not for production
|
||||
3. **No committed TODOs** - Fix or remove before commit
|
||||
4. **No merge markers** - Resolve conflicts completely
|
||||
5. **Lint compliance** - Follow project style
|
||||
|
||||
These checks ensure high code quality and prevent common mistakes.
|
||||
419
commands/commit-best-practices/revert-guidance.md
Normal file
419
commands/commit-best-practices/revert-guidance.md
Normal file
@@ -0,0 +1,419 @@
|
||||
# Operation: Commit Revert Guidance
|
||||
|
||||
Guide users through safely reverting commits with proper formatting and workflow.
|
||||
|
||||
## Parameters from $ARGUMENTS
|
||||
|
||||
- **commit** (required): Commit SHA to revert
|
||||
|
||||
Parse as: `revert-guidance commit:abc123`
|
||||
|
||||
## Revert Workflow
|
||||
|
||||
### Step 1: Validate Commit
|
||||
|
||||
Verify commit exists and get details:
|
||||
|
||||
```bash
|
||||
# Check if commit exists
|
||||
if ! git rev-parse --verify ${commit} >/dev/null 2>&1; then
|
||||
ERROR: "Commit not found: ${commit}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get commit details
|
||||
commit_sha=$(git rev-parse ${commit})
|
||||
commit_subject=$(git log -1 --format='%s' ${commit_sha})
|
||||
commit_author=$(git log -1 --format='%an <%ae>' ${commit_sha})
|
||||
commit_date=$(git log -1 --format='%ad' ${commit_sha})
|
||||
```
|
||||
|
||||
### Step 2: Run Revert Helper Script
|
||||
|
||||
Generate proper revert commit message:
|
||||
|
||||
```bash
|
||||
./.claude/commands/commit-best-practices/.scripts/revert-helper.sh "${commit_sha}"
|
||||
```
|
||||
|
||||
Returns:
|
||||
```json
|
||||
{
|
||||
"commit": "abc123...",
|
||||
"original_message": "feat(auth): add OAuth authentication",
|
||||
"revert_message": "revert: feat(auth): add OAuth authentication\n\nThis reverts commit abc123.\n\nReason: OAuth implementation incompatible with current auth system",
|
||||
"type": "feat",
|
||||
"scope": "auth",
|
||||
"files_affected": 5,
|
||||
"safe_to_revert": true,
|
||||
"warnings": []
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Analyze Revert Safety
|
||||
|
||||
Check if revert will cause issues:
|
||||
|
||||
**Safe to revert:**
|
||||
```
|
||||
✅ Safe to revert
|
||||
|
||||
Commit: abc123
|
||||
Original: feat(auth): add OAuth authentication
|
||||
Author: John Doe
|
||||
Date: 2025-10-10
|
||||
|
||||
Analysis:
|
||||
✅ No dependent commits found
|
||||
✅ No merge conflicts expected
|
||||
✅ Files still exist
|
||||
✅ Clean revert possible
|
||||
|
||||
This commit can be safely reverted.
|
||||
```
|
||||
|
||||
**Potential issues:**
|
||||
```
|
||||
⚠️ Revert with caution
|
||||
|
||||
Commit: abc123
|
||||
Original: feat(auth): add OAuth authentication
|
||||
Author: John Doe
|
||||
Date: 2025-10-10
|
||||
|
||||
Warnings:
|
||||
⚠️ 3 commits depend on this change
|
||||
- def456: feat(auth): add OAuth providers
|
||||
- ghi789: fix(auth): OAuth token refresh
|
||||
- jkl012: docs: OAuth setup guide
|
||||
|
||||
⚠️ Potential merge conflicts
|
||||
- src/auth/oauth.js: modified in later commits
|
||||
- src/config/auth.js: modified in later commits
|
||||
|
||||
Reverting will require:
|
||||
1. Resolving merge conflicts
|
||||
2. Possibly reverting dependent commits first
|
||||
3. Updating or removing affected features
|
||||
|
||||
Consider: Revert dependent commits in reverse order.
|
||||
```
|
||||
|
||||
### Step 4: Generate Revert Message
|
||||
|
||||
Follow proper revert commit message format:
|
||||
|
||||
```
|
||||
Conventional Commits Revert Format:
|
||||
-----------------------------------
|
||||
revert: <original-type>(<original-scope>): <original-subject>
|
||||
|
||||
This reverts commit <sha>.
|
||||
|
||||
Reason: <explanation-of-why>
|
||||
|
||||
[Optional: Additional context]
|
||||
[Optional: BREAKING CHANGE if revert breaks functionality]
|
||||
[Optional: Issue references]
|
||||
|
||||
Example:
|
||||
-----------------------------------
|
||||
revert: feat(auth): add OAuth authentication
|
||||
|
||||
This reverts commit abc123def456789.
|
||||
|
||||
Reason: OAuth implementation incompatible with existing SAML
|
||||
authentication system. Caused authentication failures for
|
||||
enterprise users.
|
||||
|
||||
Need to redesign OAuth to work alongside SAML before
|
||||
reintroducing.
|
||||
|
||||
BREAKING CHANGE: OAuth authentication temporarily removed.
|
||||
Users must use username/password authentication.
|
||||
|
||||
Refs: #456
|
||||
```
|
||||
|
||||
### Step 5: Provide Revert Instructions
|
||||
|
||||
**Simple revert (no conflicts):**
|
||||
|
||||
```
|
||||
How to Revert Commit
|
||||
====================
|
||||
|
||||
Commit to revert: abc123
|
||||
Original message: feat(auth): add OAuth authentication
|
||||
|
||||
Generated revert message:
|
||||
---
|
||||
revert: feat(auth): add OAuth authentication
|
||||
|
||||
This reverts commit abc123.
|
||||
|
||||
Reason: [Provide reason here]
|
||||
---
|
||||
|
||||
Option 1: Auto-revert with Git (Recommended)
|
||||
---------------------------------------------
|
||||
git revert abc123
|
||||
|
||||
This will:
|
||||
1. Create revert commit automatically
|
||||
2. Open editor for message (pre-filled)
|
||||
3. Add reason for revert
|
||||
4. Save and close
|
||||
|
||||
Option 2: Manual revert
|
||||
-----------------------
|
||||
1. git revert --no-commit abc123
|
||||
2. Review changes: git diff --cached
|
||||
3. Adjust if needed
|
||||
4. git commit (use message above)
|
||||
|
||||
After reverting:
|
||||
----------------
|
||||
1. Test that functionality is restored
|
||||
2. Verify no broken dependencies
|
||||
3. Push: git push origin <branch>
|
||||
|
||||
The revert commit preserves history while undoing changes.
|
||||
```
|
||||
|
||||
**Complex revert (conflicts or dependencies):**
|
||||
|
||||
```
|
||||
Complex Revert Required
|
||||
=======================
|
||||
|
||||
Commit to revert: abc123
|
||||
Original: feat(auth): add OAuth authentication
|
||||
Dependencies: 3 commits depend on this
|
||||
|
||||
Revert Strategy:
|
||||
----------------
|
||||
|
||||
Step 1: Revert dependent commits FIRST (newest to oldest)
|
||||
git revert jkl012 # docs: OAuth setup guide
|
||||
git revert ghi789 # fix(auth): OAuth token refresh
|
||||
git revert def456 # feat(auth): add OAuth providers
|
||||
|
||||
Step 2: Revert original commit
|
||||
git revert abc123 # feat(auth): add OAuth authentication
|
||||
|
||||
Step 3: Handle conflicts
|
||||
If conflicts occur:
|
||||
1. git status (see conflicted files)
|
||||
2. Edit files to resolve conflicts
|
||||
3. git add <resolved-files>
|
||||
4. git revert --continue
|
||||
|
||||
Step 4: Test thoroughly
|
||||
- Run full test suite
|
||||
- Verify auth system works
|
||||
- Check for broken functionality
|
||||
|
||||
Alternative: Revert in single commit
|
||||
-------------------------------------
|
||||
If you want one revert commit for all:
|
||||
|
||||
1. git revert --no-commit jkl012
|
||||
2. git revert --no-commit ghi789
|
||||
3. git revert --no-commit def456
|
||||
4. git revert --no-commit abc123
|
||||
5. Resolve any conflicts
|
||||
6. git commit -m "revert: OAuth authentication feature
|
||||
|
||||
This reverts commits abc123, def456, ghi789, jkl012.
|
||||
|
||||
Reason: OAuth incompatible with SAML system."
|
||||
|
||||
This creates a single revert commit for multiple changes.
|
||||
```
|
||||
|
||||
### Step 6: Post-Revert Checklist
|
||||
|
||||
After reverting, verify:
|
||||
|
||||
```
|
||||
Post-Revert Checklist
|
||||
=====================
|
||||
|
||||
□ Revert commit created successfully
|
||||
git log -1 (verify revert commit exists)
|
||||
|
||||
□ Changes actually reverted
|
||||
git diff <commit>^..<commit> (should be inverse of original)
|
||||
|
||||
□ Tests pass
|
||||
npm test (or your test command)
|
||||
|
||||
□ No broken functionality
|
||||
Test affected features manually
|
||||
|
||||
□ Documentation updated
|
||||
Update docs if feature was documented
|
||||
|
||||
□ Team notified
|
||||
Inform team of revert and reason
|
||||
|
||||
□ Issue tracker updated
|
||||
Comment on related issues
|
||||
|
||||
□ Ready to push
|
||||
git push origin <branch>
|
||||
```
|
||||
|
||||
## Revert vs Reset vs Amend
|
||||
|
||||
**Use `git revert` when:**
|
||||
- ✅ Commit already pushed to remote
|
||||
- ✅ Working on shared branch
|
||||
- ✅ Need to preserve history
|
||||
- ✅ Undoing specific commit in middle of history
|
||||
|
||||
**Use `git reset` when:**
|
||||
- ⚠️ Commit not yet pushed (local only)
|
||||
- ⚠️ Want to completely remove commit
|
||||
- ⚠️ Rewriting personal branch history
|
||||
- ⚠️ No one else has the commit
|
||||
|
||||
**Use `git commit --amend` when:**
|
||||
- ⚠️ Fixing most recent commit only
|
||||
- ⚠️ Commit not yet pushed
|
||||
- ⚠️ Small typo or forgotten file
|
||||
|
||||
**Decision tree:**
|
||||
```
|
||||
Has commit been pushed?
|
||||
├─ Yes → Use git revert (safe for shared history)
|
||||
└─ No → Is it the most recent commit?
|
||||
├─ Yes → Use git commit --amend (if minor fix)
|
||||
└─ No → Use git reset (if complete removal needed)
|
||||
```
|
||||
|
||||
## Revert Message Examples
|
||||
|
||||
**Example 1: Bug found**
|
||||
```
|
||||
revert: fix(api): add null check in user endpoint
|
||||
|
||||
This reverts commit abc123.
|
||||
|
||||
Reason: Fix introduced regression causing authentication
|
||||
failures for legacy clients. Null check logic incorrect.
|
||||
|
||||
Will reimplement with proper validation after adding tests.
|
||||
|
||||
Fixes: #789
|
||||
```
|
||||
|
||||
**Example 2: Performance issue**
|
||||
```
|
||||
revert: perf(search): implement new search algorithm
|
||||
|
||||
This reverts commit def456.
|
||||
|
||||
Reason: New algorithm causes 300% increase in database
|
||||
load under production traffic. Needs optimization before
|
||||
redeployment.
|
||||
|
||||
Keeping old algorithm until performance issues resolved.
|
||||
```
|
||||
|
||||
**Example 3: Breaking change**
|
||||
```
|
||||
revert: feat(api): change authentication endpoint format
|
||||
|
||||
This reverts commit ghi789.
|
||||
|
||||
Reason: Breaking change deployed without proper migration
|
||||
period. Mobile app version 1.x incompatible with new format.
|
||||
|
||||
BREAKING CHANGE: Reverting API format to v1 for backwards
|
||||
compatibility. Will reintroduce in v2 with migration path.
|
||||
|
||||
Refs: #234, #235, #236 (user reports)
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
Revert Guidance Report
|
||||
======================
|
||||
|
||||
Commit to Revert: <sha>
|
||||
Original Message: <message>
|
||||
Author: <name>
|
||||
Date: <date>
|
||||
|
||||
REVERT SAFETY:
|
||||
[✅|⚠️] No dependent commits
|
||||
[✅|⚠️] No merge conflicts expected
|
||||
[✅|⚠️] Files still exist
|
||||
|
||||
GENERATED REVERT MESSAGE:
|
||||
---
|
||||
<revert-message-content>
|
||||
---
|
||||
|
||||
REVERT INSTRUCTIONS:
|
||||
[Step-by-step instructions]
|
||||
|
||||
POST-REVERT CHECKLIST:
|
||||
[Verification steps]
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Commit not found:**
|
||||
```
|
||||
ERROR: Commit not found: abc123
|
||||
Check: git log (to see available commits)
|
||||
Verify: Commit hash is correct (7+ characters)
|
||||
```
|
||||
|
||||
**Already reverted:**
|
||||
```
|
||||
WARNING: This commit may already be reverted
|
||||
|
||||
Found revert commit: xyz789
|
||||
Message: "revert: feat(auth): add OAuth authentication"
|
||||
|
||||
If this is a duplicate revert, it may cause issues.
|
||||
Check: git log (to verify)
|
||||
```
|
||||
|
||||
**Merge commit:**
|
||||
```
|
||||
WARNING: This is a merge commit
|
||||
|
||||
Merge commits require special handling:
|
||||
git revert -m 1 abc123
|
||||
|
||||
-m 1: Keep changes from first parent
|
||||
-m 2: Keep changes from second parent
|
||||
|
||||
Determine which parent to keep based on your branch strategy.
|
||||
```
|
||||
|
||||
## Integration with Agent
|
||||
|
||||
When user says "revert my commit" or "undo commit abc123":
|
||||
1. Agent identifies commit to revert
|
||||
2. Runs safety analysis
|
||||
3. Generates proper revert message
|
||||
4. Provides step-by-step instructions
|
||||
5. Offers post-revert verification checklist
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always provide reason**: Explain WHY reverting in message
|
||||
2. **Reference original commit**: Include SHA in revert message
|
||||
3. **Test after revert**: Ensure functionality restored
|
||||
4. **Notify team**: Communicate reverts to collaborators
|
||||
5. **Update issues**: Comment on related issue tracker items
|
||||
6. **Preserve history**: Use revert, not reset, for shared branches
|
||||
|
||||
Proper reverts maintain clear history and facilitate collaboration.
|
||||
347
commands/commit-best-practices/review-commit.md
Normal file
347
commands/commit-best-practices/review-commit.md
Normal file
@@ -0,0 +1,347 @@
|
||||
# Operation: Review Commit Quality
|
||||
|
||||
Analyze a commit's quality including message, changes, atomicity, and completeness.
|
||||
|
||||
## Parameters from $ARGUMENTS
|
||||
|
||||
- **commit** (optional): Commit SHA or reference (default: HEAD)
|
||||
|
||||
Parse as: `review-commit commit:abc123` or `review-commit` (defaults to HEAD)
|
||||
|
||||
## Commit Review Workflow
|
||||
|
||||
### Step 1: Validate Commit Exists
|
||||
|
||||
```bash
|
||||
# Check if commit exists
|
||||
if ! git rev-parse --verify ${commit:-HEAD} >/dev/null 2>&1; then
|
||||
ERROR: "Commit not found: ${commit}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get commit hash
|
||||
commit_sha=$(git rev-parse ${commit:-HEAD})
|
||||
```
|
||||
|
||||
### Step 2: Run Commit Reviewer Script
|
||||
|
||||
Execute comprehensive analysis:
|
||||
|
||||
```bash
|
||||
./.claude/commands/commit-best-practices/.scripts/commit-reviewer.py "${commit_sha}"
|
||||
```
|
||||
|
||||
The script returns JSON:
|
||||
```json
|
||||
{
|
||||
"commit": "abc123...",
|
||||
"author": "John Doe <john@example.com>",
|
||||
"date": "2025-10-13",
|
||||
"message": {
|
||||
"subject": "feat(auth): add OAuth authentication",
|
||||
"body": "- Implement OAuth2 flow\n- Add providers",
|
||||
"subject_length": 38,
|
||||
"has_body": true,
|
||||
"conventional": true,
|
||||
"type": "feat",
|
||||
"scope": "auth"
|
||||
},
|
||||
"changes": {
|
||||
"files_changed": 5,
|
||||
"insertions": 234,
|
||||
"deletions": 12,
|
||||
"test_files": 1,
|
||||
"doc_files": 0
|
||||
},
|
||||
"quality": {
|
||||
"atomic": true,
|
||||
"message_quality": "excellent",
|
||||
"test_coverage": true,
|
||||
"issues": []
|
||||
},
|
||||
"score": 95
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Analyze Message Quality
|
||||
|
||||
**Check Subject Line:**
|
||||
- Length ≤ 50 characters ✅
|
||||
- Imperative mood ("add" not "added") ✅
|
||||
- Conventional commits format ✅
|
||||
- Clear and descriptive ✅
|
||||
|
||||
**Check Body (if present):**
|
||||
- Wrapped at 72 characters ✅
|
||||
- Explains WHY (not just what) ✅
|
||||
- Uses bullet points for clarity ✅
|
||||
- Blank line after subject ✅
|
||||
|
||||
**Check Footer (if present):**
|
||||
- Breaking changes noted ✅
|
||||
- Issue references included ✅
|
||||
|
||||
### Step 4: Analyze Changes
|
||||
|
||||
**Atomicity Check:**
|
||||
```
|
||||
Atomic commit = Single logical change
|
||||
|
||||
Check for:
|
||||
❌ Multiple types mixed (feat + fix)
|
||||
❌ Multiple scopes mixed (auth + api + docs)
|
||||
❌ Unrelated changes bundled together
|
||||
|
||||
Example ATOMIC:
|
||||
feat(auth): add OAuth authentication
|
||||
- 5 files, all auth-related
|
||||
- Single feature implementation
|
||||
|
||||
Example NON-ATOMIC:
|
||||
feat: add OAuth and fix null pointer
|
||||
- Mixing feat + fix
|
||||
- Should be 2 commits
|
||||
```
|
||||
|
||||
**Completeness Check:**
|
||||
```
|
||||
Complete commit includes:
|
||||
✅ Implementation code
|
||||
✅ Tests for new code
|
||||
✅ Documentation if needed
|
||||
✅ No missing pieces
|
||||
|
||||
Incomplete examples:
|
||||
❌ New feature without tests
|
||||
❌ API change without docs
|
||||
❌ Partial implementation
|
||||
```
|
||||
|
||||
### Step 5: Generate Review Report
|
||||
|
||||
**Excellent Commit (Score 90-100):**
|
||||
```
|
||||
✅ EXCELLENT COMMIT
|
||||
|
||||
Commit: abc123 (HEAD)
|
||||
Author: John Doe
|
||||
Date: 2025-10-13
|
||||
|
||||
Message Quality: EXCELLENT
|
||||
✅ Subject: "feat(auth): add OAuth authentication" (38 chars)
|
||||
✅ Conventional commits format
|
||||
✅ Descriptive body with bullet points
|
||||
✅ Proper formatting
|
||||
|
||||
Changes:
|
||||
✅ Atomic: Single feature (OAuth authentication)
|
||||
✅ Complete: Implementation + tests
|
||||
✅ Files: 5 changed (+234 -12 lines)
|
||||
✅ Test coverage included
|
||||
|
||||
Score: 95/100
|
||||
|
||||
This commit follows all best practices. Safe to push!
|
||||
```
|
||||
|
||||
**Good Commit (Score 70-89):**
|
||||
```
|
||||
✅ GOOD COMMIT (Minor improvements possible)
|
||||
|
||||
Commit: abc123 (HEAD)
|
||||
Author: John Doe
|
||||
Date: 2025-10-13
|
||||
|
||||
Message Quality: GOOD
|
||||
✅ Subject: "feat(auth): add OAuth authentication" (38 chars)
|
||||
✅ Conventional commits format
|
||||
⚠️ Body: Could be more detailed (explains WHAT but not WHY)
|
||||
|
||||
Changes:
|
||||
✅ Atomic: Single feature
|
||||
⚠️ Test coverage: Only integration tests (unit tests missing)
|
||||
✅ Files: 5 changed (+234 -12 lines)
|
||||
|
||||
Score: 82/100
|
||||
|
||||
Suggestions:
|
||||
1. Add more context in commit body about WHY this change
|
||||
2. Consider adding unit tests for edge cases
|
||||
|
||||
Still a good commit. Safe to push with minor notes.
|
||||
```
|
||||
|
||||
**Needs Improvement (Score 50-69):**
|
||||
```
|
||||
⚠️ NEEDS IMPROVEMENT
|
||||
|
||||
Commit: abc123 (HEAD)
|
||||
Author: John Doe
|
||||
Date: 2025-10-13
|
||||
|
||||
Message Quality: FAIR
|
||||
⚠️ Subject: "add oauth" (9 chars - too short)
|
||||
❌ Not conventional commits format (missing type/scope)
|
||||
❌ No body explaining changes
|
||||
|
||||
Changes:
|
||||
⚠️ Atomicity: Questionable (mixes auth + API changes)
|
||||
❌ Test coverage: No tests included
|
||||
✅ Files: 8 changed (+312 -45 lines)
|
||||
|
||||
Score: 58/100
|
||||
|
||||
Issues to address:
|
||||
1. Improve commit message: "feat(auth): add OAuth authentication"
|
||||
2. Add commit body explaining implementation
|
||||
3. Add tests for new OAuth functionality
|
||||
4. Consider splitting auth changes from API changes
|
||||
|
||||
Recommendation: Amend or rewrite this commit before pushing.
|
||||
```
|
||||
|
||||
**Poor Commit (Score < 50):**
|
||||
```
|
||||
❌ POOR COMMIT - Should be rewritten
|
||||
|
||||
Commit: abc123 (HEAD)
|
||||
Author: John Doe
|
||||
Date: 2025-10-13
|
||||
|
||||
Message Quality: POOR
|
||||
❌ Subject: "stuff" (5 chars - meaningless)
|
||||
❌ No type, no scope, no clarity
|
||||
❌ No body, no context
|
||||
|
||||
Changes:
|
||||
❌ Non-atomic: Multiple unrelated changes
|
||||
- Auth system
|
||||
- API refactoring
|
||||
- Documentation
|
||||
- Bug fixes (3 different issues)
|
||||
❌ No tests
|
||||
❌ Files: 23 changed (+1,234 -567 lines)
|
||||
|
||||
Score: 28/100
|
||||
|
||||
Critical issues:
|
||||
1. Commit message is meaningless ("stuff")
|
||||
2. Bundles 4+ unrelated changes together
|
||||
3. No tests for significant code changes
|
||||
4. Too large (23 files)
|
||||
|
||||
Action required: Reset and split into 4+ atomic commits with proper messages.
|
||||
|
||||
Use: /commit-split (to split into atomic commits)
|
||||
```
|
||||
|
||||
### Step 6: Provide Actionable Guidance
|
||||
|
||||
Based on score, recommend action:
|
||||
|
||||
**Score ≥ 90**: Safe to push as-is
|
||||
**Score 70-89**: Safe to push, minor suggestions noted
|
||||
**Score 50-69**: Amend recommended before pushing
|
||||
**Score < 50**: Rewrite required, do not push
|
||||
|
||||
## Amend Guidance
|
||||
|
||||
If commit needs improvement and is safe to amend:
|
||||
|
||||
```
|
||||
To amend this commit:
|
||||
|
||||
1. Make improvements (add tests, update message, etc.)
|
||||
2. Stage changes: git add <files>
|
||||
3. Amend commit: git commit --amend
|
||||
4. Review again: /commit-best-practices review-commit
|
||||
|
||||
Note: Only amend if commit not yet pushed to remote!
|
||||
Check: /commit-best-practices amend-guidance
|
||||
```
|
||||
|
||||
## Split Guidance
|
||||
|
||||
If commit is non-atomic:
|
||||
|
||||
```
|
||||
This commit should be split into multiple commits:
|
||||
|
||||
Detected separate concerns:
|
||||
1. feat(auth): OAuth implementation (5 files)
|
||||
2. fix(api): null pointer handling (2 files)
|
||||
3. docs: authentication guide (1 file)
|
||||
|
||||
Use: /commit-split (for interactive splitting)
|
||||
Or: git reset HEAD~1 (to undo and recommit properly)
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
Commit Review Report
|
||||
===================
|
||||
|
||||
Commit: <sha> (<ref>)
|
||||
Author: <name> <email>
|
||||
Date: <date>
|
||||
|
||||
MESSAGE QUALITY: [EXCELLENT|GOOD|FAIR|POOR]
|
||||
[✅|⚠️|❌] Subject: "<subject>" (<length> chars)
|
||||
[✅|⚠️|❌] Format: [Conventional|Non-conventional]
|
||||
[✅|⚠️|❌] Body: [Present|Missing]
|
||||
[✅|⚠️|❌] Clarity: [Clear|Vague]
|
||||
|
||||
CHANGES:
|
||||
[✅|⚠️|❌] Atomic: [Yes|Questionable|No]
|
||||
[✅|⚠️|❌] Complete: [Yes|Partial]
|
||||
[✅|⚠️|❌] Tests: [Included|Missing]
|
||||
[✅|⚠️|❌] Size: <files> files (+<ins> -<del> lines)
|
||||
|
||||
SCORE: <score>/100
|
||||
|
||||
[Issues list if any]
|
||||
|
||||
[Recommendations]
|
||||
|
||||
VERDICT: [Safe to push|Amend recommended|Rewrite required]
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Commit not found:**
|
||||
```
|
||||
ERROR: Commit not found: abc123
|
||||
Check: git log (to see available commits)
|
||||
```
|
||||
|
||||
**Not a git repository:**
|
||||
```
|
||||
ERROR: Not a git repository
|
||||
Run: git init (to initialize)
|
||||
```
|
||||
|
||||
**Script execution error:**
|
||||
```
|
||||
ERROR: Commit reviewer script failed
|
||||
Check: .claude/commands/commit-best-practices/.scripts/commit-reviewer.py exists
|
||||
Verify: Script is executable
|
||||
```
|
||||
|
||||
## Integration with Agent
|
||||
|
||||
After user creates a commit:
|
||||
1. Agent automatically runs review (unless disabled)
|
||||
2. If score < 70, suggest improvements
|
||||
3. If non-atomic, suggest splitting
|
||||
4. If excellent (≥90), congratulate and suggest push
|
||||
|
||||
## Best Practices Enforced
|
||||
|
||||
1. **Meaningful messages** - Clear, descriptive commit messages
|
||||
2. **Conventional format** - type(scope): description
|
||||
3. **Atomic commits** - One logical change per commit
|
||||
4. **Complete commits** - Include tests and docs
|
||||
5. **Proper formatting** - Subject ≤50 chars, body wrapped at 72
|
||||
|
||||
High-quality commits make git history useful for debugging, code review, and collaboration.
|
||||
78
commands/commit-best-practices/skill.md
Normal file
78
commands/commit-best-practices/skill.md
Normal file
@@ -0,0 +1,78 @@
|
||||
---
|
||||
description: Enforce git commit best practices and workflow guidance
|
||||
---
|
||||
|
||||
# Commit Best Practices Skill Router
|
||||
|
||||
You are orchestrating commit best practices validation and workflow guidance operations.
|
||||
|
||||
## Parse Request
|
||||
|
||||
Examine `$ARGUMENTS` to determine the operation and parameters:
|
||||
|
||||
**Format**: `<operation> [parameters]`
|
||||
|
||||
## Available Operations
|
||||
|
||||
1. **check-pre-commit** - Validate repository state before committing
|
||||
- Runs tests, lint checks, detects debug code
|
||||
- Validates no TODOs, no merge markers
|
||||
- Format: `check-pre-commit [quick:true|false]`
|
||||
|
||||
2. **review-commit** - Review most recent commit quality
|
||||
- Analyzes commit message and changes
|
||||
- Checks atomicity and completeness
|
||||
- Format: `review-commit [commit:HEAD|<sha>]`
|
||||
|
||||
3. **amend-guidance** - Guide safe commit amending
|
||||
- Checks if safe to amend (not pushed, same author)
|
||||
- Provides amend instructions
|
||||
- Format: `amend-guidance [force:true|false]`
|
||||
|
||||
4. **revert-guidance** - Help with commit reverts
|
||||
- Generates proper revert commit message
|
||||
- Provides revert instructions
|
||||
- Format: `revert-guidance commit:<sha>`
|
||||
|
||||
5. **workflow-tips** - Complete git workflow guidance
|
||||
- Best practices overview
|
||||
- Branch management tips
|
||||
- Format: `workflow-tips [focus:commit|branch|merge]`
|
||||
|
||||
## Routing Logic
|
||||
|
||||
```
|
||||
Parse first word from $ARGUMENTS:
|
||||
"check-pre-commit" → Read commands/commit-best-practices/check-pre-commit.md
|
||||
"review-commit" → Read commands/commit-best-practices/review-commit.md
|
||||
"amend-guidance" → Read commands/commit-best-practices/amend-guidance.md
|
||||
"revert-guidance" → Read commands/commit-best-practices/revert-guidance.md
|
||||
"workflow-tips" → Read commands/commit-best-practices/workflow-tips.md
|
||||
(unknown) → Show error and list available operations
|
||||
```
|
||||
|
||||
## Base Directory
|
||||
|
||||
**Location**: `.claude/commands/commit-best-practices/`
|
||||
|
||||
## Error Handling
|
||||
|
||||
If operation is not recognized:
|
||||
```
|
||||
ERROR: Unknown operation: <operation>
|
||||
|
||||
Available operations:
|
||||
- check-pre-commit [quick:true|false]
|
||||
- review-commit [commit:HEAD|<sha>]
|
||||
- amend-guidance [force:true|false]
|
||||
- revert-guidance commit:<sha>
|
||||
- workflow-tips [focus:commit|branch|merge]
|
||||
|
||||
Example: /commit-best-practices check-pre-commit quick:true
|
||||
```
|
||||
|
||||
## Request Context
|
||||
|
||||
**User Request**: `$ARGUMENTS`
|
||||
|
||||
Now route to the appropriate operation file and execute its instructions with the provided parameters.
|
||||
607
commands/commit-best-practices/workflow-tips.md
Normal file
607
commands/commit-best-practices/workflow-tips.md
Normal file
@@ -0,0 +1,607 @@
|
||||
# Operation: Git Workflow Tips and Best Practices
|
||||
|
||||
Comprehensive git workflow guidance covering commits, branches, merging, and collaboration.
|
||||
|
||||
## Parameters from $ARGUMENTS
|
||||
|
||||
- **focus** (optional): Specific area (commit|branch|merge|all) (default: all)
|
||||
|
||||
Parse as: `workflow-tips focus:commit` or `workflow-tips`
|
||||
|
||||
## Workflow Guidance
|
||||
|
||||
Route to specific section based on focus parameter:
|
||||
|
||||
### Focus: Commit Workflow
|
||||
|
||||
**Complete commit workflow best practices:**
|
||||
|
||||
```
|
||||
Git Commit Workflow Best Practices
|
||||
===================================
|
||||
|
||||
1. BEFORE YOU CODE
|
||||
------------------
|
||||
□ Create feature branch
|
||||
git checkout -b feature/your-feature-name
|
||||
|
||||
□ Pull latest changes
|
||||
git pull origin main
|
||||
|
||||
□ Verify clean state
|
||||
git status
|
||||
|
||||
|
||||
2. WHILE CODING
|
||||
---------------
|
||||
□ Commit frequently (atomic commits)
|
||||
- After each logical change
|
||||
- Not too small (typo fixes can be bundled)
|
||||
- Not too large (avoid 1000+ line commits)
|
||||
|
||||
□ Test before committing
|
||||
npm test (or your test command)
|
||||
|
||||
□ Keep commits focused
|
||||
- One concern per commit
|
||||
- Don't mix features and fixes
|
||||
- Don't mix multiple scopes
|
||||
|
||||
|
||||
3. BEFORE COMMITTING
|
||||
--------------------
|
||||
□ Review your changes
|
||||
git diff (see what changed)
|
||||
git status (see staged/unstaged)
|
||||
|
||||
□ Stage selectively
|
||||
git add <specific-files>
|
||||
(Don't blindly: git add .)
|
||||
|
||||
□ Run pre-commit checks
|
||||
/commit-best-practices check-pre-commit
|
||||
|
||||
□ Remove debug code
|
||||
- console.log, print statements
|
||||
- debugger statements
|
||||
- Temporary test code
|
||||
|
||||
|
||||
4. CREATING COMMIT
|
||||
------------------
|
||||
□ Use conventional commits format
|
||||
<type>(<scope>): <subject>
|
||||
|
||||
□ Write clear subject (≤50 chars)
|
||||
- Imperative mood: "add" not "added"
|
||||
- Lowercase after type
|
||||
- No period at end
|
||||
|
||||
□ Add descriptive body (if needed)
|
||||
- Explain WHY, not what
|
||||
- Wrap at 72 characters
|
||||
- Use bullet points
|
||||
|
||||
□ Include footer (if applicable)
|
||||
- BREAKING CHANGE: description
|
||||
- Closes #123
|
||||
|
||||
|
||||
5. AFTER COMMITTING
|
||||
-------------------
|
||||
□ Review commit
|
||||
/commit-best-practices review-commit
|
||||
git show HEAD
|
||||
|
||||
□ Verify tests still pass
|
||||
npm test
|
||||
|
||||
□ Push to remote
|
||||
git push origin <branch>
|
||||
|
||||
□ Create pull request (if ready)
|
||||
gh pr create
|
||||
|
||||
|
||||
6. COMMON MISTAKES TO AVOID
|
||||
---------------------------
|
||||
❌ "WIP" or "work in progress" commits
|
||||
→ Finish work before committing
|
||||
|
||||
❌ "Fix" or "update" without context
|
||||
→ Be specific: "fix(auth): null pointer in OAuth"
|
||||
|
||||
❌ Committing all changes at once
|
||||
→ Split into atomic commits
|
||||
|
||||
❌ Forgetting to add tests
|
||||
→ Tests should accompany code changes
|
||||
|
||||
❌ Committing node_modules or .env files
|
||||
→ Use .gitignore properly
|
||||
|
||||
❌ Force pushing to shared branches
|
||||
→ Only force push on personal branches
|
||||
|
||||
|
||||
7. COMMIT CHECKLIST
|
||||
-------------------
|
||||
Before every commit, verify:
|
||||
|
||||
□ Changes are atomic (single logical change)
|
||||
□ Tests pass
|
||||
□ No debug code
|
||||
□ No TODOs in committed code
|
||||
□ Message follows conventions
|
||||
□ Includes tests (if new functionality)
|
||||
□ Documentation updated (if needed)
|
||||
|
||||
Use: /commit (agent handles checklist automatically)
|
||||
```
|
||||
|
||||
### Focus: Branch Workflow
|
||||
|
||||
**Branch management best practices:**
|
||||
|
||||
```
|
||||
Git Branch Workflow Best Practices
|
||||
===================================
|
||||
|
||||
1. BRANCH NAMING CONVENTIONS
|
||||
-----------------------------
|
||||
Follow consistent naming:
|
||||
|
||||
Feature branches:
|
||||
feature/oauth-authentication
|
||||
feature/user-profile-page
|
||||
|
||||
Bug fixes:
|
||||
fix/null-pointer-in-auth
|
||||
fix/memory-leak-in-parser
|
||||
|
||||
Hotfixes:
|
||||
hotfix/security-vulnerability
|
||||
hotfix/production-crash
|
||||
|
||||
Experiments:
|
||||
experiment/new-algorithm
|
||||
experiment/performance-optimization
|
||||
|
||||
Pattern: <type>/<brief-description>
|
||||
Use: lowercase-with-hyphens
|
||||
|
||||
|
||||
2. BRANCH LIFECYCLE
|
||||
-------------------
|
||||
Create → Develop → Test → Merge → Delete
|
||||
|
||||
Create:
|
||||
git checkout -b feature/my-feature
|
||||
(Always branch from main/develop)
|
||||
|
||||
Develop:
|
||||
- Commit frequently
|
||||
- Push regularly
|
||||
- Keep branch updated
|
||||
|
||||
Test:
|
||||
- Run full test suite
|
||||
- Manual testing
|
||||
- Code review
|
||||
|
||||
Merge:
|
||||
- Create pull request
|
||||
- Address review feedback
|
||||
- Merge to main
|
||||
|
||||
Delete:
|
||||
git branch -d feature/my-feature
|
||||
git push origin --delete feature/my-feature
|
||||
|
||||
|
||||
3. KEEPING BRANCHES UPDATED
|
||||
---------------------------
|
||||
Regularly sync with main branch:
|
||||
|
||||
Option 1: Rebase (cleaner history)
|
||||
git checkout feature/my-feature
|
||||
git fetch origin
|
||||
git rebase origin/main
|
||||
|
||||
Option 2: Merge (preserves history)
|
||||
git checkout feature/my-feature
|
||||
git merge origin/main
|
||||
|
||||
Recommendation: Use rebase for feature branches,
|
||||
merge for shared branches.
|
||||
|
||||
|
||||
4. BRANCH PROTECTION RULES
|
||||
---------------------------
|
||||
Protect important branches:
|
||||
|
||||
Main/Master:
|
||||
- Require pull request
|
||||
- Require code review
|
||||
- Require passing tests
|
||||
- Block force push
|
||||
- Block deletion
|
||||
|
||||
Develop:
|
||||
- Require pull request
|
||||
- Require passing tests
|
||||
- Allow force push with lease
|
||||
|
||||
Feature:
|
||||
- No restrictions
|
||||
- Personal branches
|
||||
|
||||
|
||||
5. LONG-RUNNING BRANCHES
|
||||
-------------------------
|
||||
If branch lives more than a few days:
|
||||
|
||||
□ Sync with main frequently (daily)
|
||||
□ Keep commits atomic and clean
|
||||
□ Push to remote regularly
|
||||
□ Communicate with team
|
||||
□ Consider splitting into smaller branches
|
||||
|
||||
|
||||
6. BRANCH STRATEGIES
|
||||
--------------------
|
||||
Choose strategy based on team size:
|
||||
|
||||
Git Flow (large teams):
|
||||
- main: production
|
||||
- develop: integration
|
||||
- feature/*: new features
|
||||
- release/*: release prep
|
||||
- hotfix/*: urgent fixes
|
||||
|
||||
GitHub Flow (small teams):
|
||||
- main: production
|
||||
- feature/*: all work
|
||||
(Simple and effective)
|
||||
|
||||
Trunk-Based (continuous deployment):
|
||||
- main: always deployable
|
||||
- Short-lived feature branches
|
||||
- Feature flags for incomplete work
|
||||
|
||||
|
||||
7. COMMON BRANCH MISTAKES
|
||||
--------------------------
|
||||
❌ Working directly on main
|
||||
→ Always use feature branches
|
||||
|
||||
❌ Branches that live for weeks
|
||||
→ Split into smaller branches
|
||||
|
||||
❌ Not syncing with main regularly
|
||||
→ Causes massive merge conflicts
|
||||
|
||||
❌ Unclear branch names (branch1, temp)
|
||||
→ Use descriptive names
|
||||
|
||||
❌ Leaving merged branches
|
||||
→ Delete after merging
|
||||
|
||||
❌ Force pushing shared branches
|
||||
→ Only force push personal branches
|
||||
```
|
||||
|
||||
### Focus: Merge Workflow
|
||||
|
||||
**Merge and pull request best practices:**
|
||||
|
||||
```
|
||||
Git Merge Workflow Best Practices
|
||||
==================================
|
||||
|
||||
1. BEFORE CREATING PULL REQUEST
|
||||
-------------------------------
|
||||
□ All commits are atomic
|
||||
/commit-review (check quality)
|
||||
|
||||
□ Branch is up-to-date
|
||||
git fetch origin
|
||||
git rebase origin/main
|
||||
|
||||
□ All tests pass
|
||||
npm test (full suite)
|
||||
|
||||
□ No merge conflicts
|
||||
Resolve before creating PR
|
||||
|
||||
□ Code is reviewed locally
|
||||
Self-review your changes
|
||||
|
||||
|
||||
2. CREATING PULL REQUEST
|
||||
------------------------
|
||||
Good PR title:
|
||||
feat(auth): Add OAuth authentication support
|
||||
|
||||
Good PR description:
|
||||
## Summary
|
||||
Implements OAuth 2.0 authentication for Google and GitHub.
|
||||
|
||||
## Changes
|
||||
- OAuth configuration system
|
||||
- Provider implementations (Google, GitHub)
|
||||
- Token refresh mechanism
|
||||
- Middleware integration
|
||||
|
||||
## Testing
|
||||
- Unit tests: 15 added
|
||||
- Integration tests: 3 added
|
||||
- Manual testing: OAuth flows verified
|
||||
|
||||
## Screenshots (if UI)
|
||||
[Include screenshots]
|
||||
|
||||
Closes #123
|
||||
|
||||
|
||||
3. CODE REVIEW PROCESS
|
||||
----------------------
|
||||
As author:
|
||||
□ Respond to all comments
|
||||
□ Make requested changes
|
||||
□ Push new commits (don't amend!)
|
||||
□ Re-request review when ready
|
||||
□ Be open to feedback
|
||||
|
||||
As reviewer:
|
||||
□ Review code thoroughly
|
||||
□ Check tests are included
|
||||
□ Verify documentation updated
|
||||
□ Test locally if possible
|
||||
□ Be constructive in feedback
|
||||
|
||||
|
||||
4. MERGE STRATEGIES
|
||||
-------------------
|
||||
Choose appropriate merge strategy:
|
||||
|
||||
Merge Commit (default):
|
||||
git merge --no-ff feature/my-feature
|
||||
- Preserves complete history
|
||||
- Shows where feature was merged
|
||||
- Creates merge commit
|
||||
Use for: Significant features
|
||||
|
||||
Squash Merge:
|
||||
git merge --squash feature/my-feature
|
||||
- Combines all commits into one
|
||||
- Clean linear history
|
||||
- Loses individual commit detail
|
||||
Use for: Small features, many WIP commits
|
||||
|
||||
Rebase Merge:
|
||||
git rebase main
|
||||
git merge --ff-only
|
||||
- Linear history
|
||||
- No merge commit
|
||||
- Clean git log
|
||||
Use for: Personal branches, small changes
|
||||
|
||||
|
||||
5. RESOLVING MERGE CONFLICTS
|
||||
-----------------------------
|
||||
When conflicts occur:
|
||||
|
||||
Step 1: Identify conflicts
|
||||
git status (shows conflicted files)
|
||||
|
||||
Step 2: Open conflicted file
|
||||
Conflict markers:
|
||||
<<<<<<< HEAD
|
||||
Your changes
|
||||
=======
|
||||
Their changes
|
||||
>>>>>>> feature/branch
|
||||
|
||||
Step 3: Resolve conflict
|
||||
- Choose one version, or
|
||||
- Combine both versions, or
|
||||
- Write new solution
|
||||
|
||||
Step 4: Remove conflict markers
|
||||
Delete <<<<<<<, =======, >>>>>>>
|
||||
|
||||
Step 5: Mark as resolved
|
||||
git add <resolved-file>
|
||||
|
||||
Step 6: Complete merge
|
||||
git merge --continue
|
||||
(or git rebase --continue)
|
||||
|
||||
Step 7: Test thoroughly
|
||||
npm test
|
||||
Manual testing
|
||||
|
||||
|
||||
6. AFTER MERGING
|
||||
----------------
|
||||
□ Delete feature branch
|
||||
git branch -d feature/my-feature
|
||||
git push origin --delete feature/my-feature
|
||||
|
||||
□ Verify merge on main
|
||||
git checkout main
|
||||
git pull origin main
|
||||
git log (verify commit appears)
|
||||
|
||||
□ Run tests on main
|
||||
npm test
|
||||
|
||||
□ Deploy if applicable
|
||||
(Follow deployment process)
|
||||
|
||||
□ Update issue tracker
|
||||
Close related issues
|
||||
|
||||
□ Notify stakeholders
|
||||
Team notification of merge
|
||||
|
||||
|
||||
7. MERGE BEST PRACTICES
|
||||
------------------------
|
||||
✅ Merge frequently (avoid long-lived branches)
|
||||
✅ Require code review before merge
|
||||
✅ Ensure tests pass before merge
|
||||
✅ Delete branches after merge
|
||||
✅ Use meaningful merge commit messages
|
||||
✅ Squash "fix review comments" commits
|
||||
|
||||
❌ Don't merge failing tests
|
||||
❌ Don't merge without review
|
||||
❌ Don't merge with unresolved conflicts
|
||||
❌ Don't merge incomplete features to main
|
||||
❌ Don't forget to pull after merge
|
||||
```
|
||||
|
||||
### Focus: All (Complete Workflow)
|
||||
|
||||
When `focus:all` or no focus specified, provide comprehensive overview:
|
||||
|
||||
```
|
||||
Complete Git Workflow Guide
|
||||
============================
|
||||
|
||||
Quick Reference for Git Best Practices
|
||||
|
||||
DAILY WORKFLOW
|
||||
--------------
|
||||
1. Start day: git pull origin main
|
||||
2. Create branch: git checkout -b feature/name
|
||||
3. Code & commit frequently (atomic commits)
|
||||
4. Test before each commit
|
||||
5. Push regularly: git push origin feature/name
|
||||
6. Create PR when ready
|
||||
7. Address review feedback
|
||||
8. Merge and delete branch
|
||||
9. Pull updated main
|
||||
|
||||
COMMIT GUIDELINES
|
||||
-----------------
|
||||
Format: <type>(<scope>): <subject>
|
||||
|
||||
Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore
|
||||
|
||||
Subject: ≤50 chars, imperative, lowercase, no period
|
||||
Body: Wrap at 72 chars, explain WHY
|
||||
Footer: BREAKING CHANGE, Closes #123
|
||||
|
||||
BRANCH STRATEGY
|
||||
---------------
|
||||
- main: production-ready code
|
||||
- feature/*: new features
|
||||
- fix/*: bug fixes
|
||||
- hotfix/*: urgent production fixes
|
||||
|
||||
Keep branches short-lived (< 1 week)
|
||||
Sync with main daily
|
||||
Delete after merging
|
||||
|
||||
MERGE PROCESS
|
||||
-------------
|
||||
1. Rebase on main: git rebase origin/main
|
||||
2. Resolve conflicts
|
||||
3. All tests pass
|
||||
4. Code review approved
|
||||
5. Merge to main
|
||||
6. Delete feature branch
|
||||
|
||||
TOOLS TO USE
|
||||
------------
|
||||
/commit - Create commit with agent assistance
|
||||
/commit-review - Review commit quality
|
||||
/commit-split - Split non-atomic commits
|
||||
/commit-best-practices check-pre-commit - Validate before commit
|
||||
/commit-best-practices review-commit - Review commit after creation
|
||||
/commit-best-practices amend-guidance - Safe amend help
|
||||
/commit-best-practices revert-guidance - Revert help
|
||||
|
||||
COMMON COMMANDS
|
||||
---------------
|
||||
git status # Check status
|
||||
git diff # See changes
|
||||
git add <files> # Stage changes
|
||||
git commit # Create commit
|
||||
git push origin <branch> # Push to remote
|
||||
git pull origin main # Get latest main
|
||||
git log --oneline -10 # Recent commits
|
||||
git show HEAD # Show last commit
|
||||
|
||||
EMERGENCY PROCEDURES
|
||||
--------------------
|
||||
Committed to wrong branch:
|
||||
git reset --soft HEAD~1
|
||||
git checkout correct-branch
|
||||
git commit
|
||||
|
||||
Pushed wrong commit:
|
||||
git revert HEAD
|
||||
git push
|
||||
|
||||
Need to undo local changes:
|
||||
git checkout -- <file>
|
||||
(or git restore <file>)
|
||||
|
||||
Accidentally deleted branch:
|
||||
git reflog
|
||||
git checkout -b branch-name <sha>
|
||||
|
||||
For more detailed guidance on specific areas:
|
||||
/commit-best-practices workflow-tips focus:commit
|
||||
/commit-best-practices workflow-tips focus:branch
|
||||
/commit-best-practices workflow-tips focus:merge
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
Provide guidance formatted with:
|
||||
- Clear section headers
|
||||
- Checkboxes for actionable items
|
||||
- Code examples with syntax highlighting
|
||||
- Visual indicators (✅ ❌ ⚠️)
|
||||
- Step-by-step instructions
|
||||
- Common pitfalls and solutions
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Invalid focus parameter:**
|
||||
```
|
||||
ERROR: Invalid focus: invalid-focus
|
||||
Valid options: commit, branch, merge, all
|
||||
Example: /commit-best-practices workflow-tips focus:commit
|
||||
```
|
||||
|
||||
## Integration with Agent
|
||||
|
||||
Proactively suggest workflow tips when:
|
||||
- User commits to main branch directly (suggest feature branch)
|
||||
- Branch hasn't been synced in 3+ days (suggest rebase)
|
||||
- PR has many commits (suggest squash)
|
||||
- User attempts unsafe operation (provide guidance)
|
||||
|
||||
## Best Practices Summary
|
||||
|
||||
**The Golden Rules:**
|
||||
|
||||
1. **Commit often** - Atomic, focused commits
|
||||
2. **Test always** - Before every commit
|
||||
3. **Branch per feature** - Isolate work
|
||||
4. **Sync regularly** - Stay updated with main
|
||||
5. **Review thoroughly** - All code reviewed
|
||||
6. **Merge cleanly** - No conflicts, passing tests
|
||||
7. **Delete branches** - After merging
|
||||
8. **Communicate** - Keep team informed
|
||||
|
||||
**Tools make it easier:**
|
||||
Use `/commit` and related skills to automate best practices and ensure consistent, high-quality commits.
|
||||
|
||||
These workflows ensure clean history, facilitate collaboration, and make debugging easier when issues arise.
|
||||
Reference in New Issue
Block a user