Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:20:25 +08:00
commit 0d6226e0d8
69 changed files with 20934 additions and 0 deletions

View 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 "$@"

View 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()

View 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 "$@"

View 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 "$@"

View 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.

View 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.

View 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.

View 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.

View 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.

View 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.

View 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.