whatchanged Git Command Guide
The git whatchanged command shows commit logs with the list of files changed in each commit, providing a compact way to see what files were modified and how. It’s particularly useful for understanding the scope of changes across multiple commits.
git whatchanged Syntax:
Section titled “git whatchanged Syntax:”git whatchanged [options] [--] [path...]Options:
Section titled “Options:”| Option | Description |
|---|---|
-p, --patch | Show patch (diff) for each commit |
--stat | Show statistics about files changed |
--name-only | Show only names of changed files |
--name-status | Show names and status of changed files |
--pretty=<format> | Pretty-print commit messages |
--oneline | Shorthand for --pretty=oneline --abbrev-commit |
--graph | Draw commit history graph |
--decorate | Show ref names of commits |
--follow | Follow file renames |
--since=<date> | Show commits since date |
--until=<date> | Show commits until date |
--author=<pattern> | Show commits by author |
--grep=<pattern> | Show commits with messages matching pattern |
-n <number> | Limit number of commits |
--reverse | Show commits in reverse order |
Parameters:
Section titled “Parameters:”| Parameter | Description |
|---|---|
<path> | Show only commits that affect specified paths |
Understanding Whatchanged Output:
Section titled “Understanding Whatchanged Output:”Output Format:
Section titled “Output Format:”Git Whatchanged Output Structure:├── Commit Header: commit hash, author, date├── Changed Files: List of modified files with status├── Diff Output: Optional patch showing changes└── File Statistics: Optional summary of changesFile Status Indicators:
Section titled “File Status Indicators:”File Change Status Codes:├── A: Added - File was added to repository├── M: Modified - File content was changed├── D: Deleted - File was removed from repository├── R: Renamed - File was renamed (shows old -> new name)├── C: Copied - File was copied from another file├── T: Type changed - File type changed (regular <-> symlink)└── U: Unmerged - File has merge conflictsComparison with Other Commands:
Section titled “Comparison with Other Commands:”Command Comparison:├── git log: Shows commit messages and metadata├── git whatchanged: Shows commit messages + changed files├── git log --name-status: Similar to whatchanged without patch└── git log --stat: Shows commit messages + file change statisticsBasic Whatchanged Operations:
Section titled “Basic Whatchanged Operations:”Show Recent Changes:
Section titled “Show Recent Changes:”# Show last 10 commits with changed filesgit whatchanged -10
# Show commits with file names onlygit whatchanged --name-only -5
# Show commits with file statusgit whatchanged --name-status -5Show Changes with Statistics:
Section titled “Show Changes with Statistics:”# Show commit statisticsgit whatchanged --stat -10
# Show detailed patch outputgit whatchanged -p -3
# Show oneline format with changesgit whatchanged --oneline --name-status -10Filter by Path:
Section titled “Filter by Path:”# Show changes to specific filegit whatchanged -- src/main.js
# Show changes to directorygit whatchanged -- src/components/
# Show changes to multiple pathsgit whatchanged -- src/ tests/Advanced Whatchanged Scenarios:
Section titled “Advanced Whatchanged Scenarios:”Time-Based Filtering:
Section titled “Time-Based Filtering:”# Show changes from last weekgit whatchanged --since="1 week ago"
# Show changes between datesgit whatchanged --since="2024-01-01" --until="2024-01-31"
# Show today's changesgit whatchanged --since="midnight"Author and Content Filtering:
Section titled “Author and Content Filtering:”# Show changes by specific authorgit whatchanged --author="John Doe"
# Show commits containing specific textgit whatchanged --grep="bug fix"
# Combine filtersgit whatchanged --author="Jane" --grep="feature" --since="1 month ago"File Change Analysis:
Section titled “File Change Analysis:”# Analyze file change patternsanalyze_file_changes() { echo "File change analysis for last 50 commits:"
git whatchanged --name-status -50 | awk ' /^commit/ {commit++} /^[AMD]/ {files[$2]++; total_changes++} END { print "Total commits analyzed:", commit print "Total file changes:", total_changes print "Files changed:" for (file in files) { print " " file ": " files[file] " changes" } } '}
# Find most frequently changed filesmost_changed_files() { echo "Most frequently changed files:"
git whatchanged --name-only -100 | grep -v '^commit' | sort | uniq -c | sort -nr | head -10}
# Usageanalyze_file_changesechomost_changed_filesCommit Impact Analysis:
Section titled “Commit Impact Analysis:”# Analyze commit impactcommit_impact_analysis() { echo "Commit impact analysis:"
# Files changed per commit echo "Files changed per commit:" git whatchanged --name-only | awk ' /^commit/ {if (NR>1) print commit, ":", count; commit=$2; count=0} /^[A-Z]/ {count++} END {print commit, ":", count} ' | head -10
# Largest commits by file changes echo -e "\nLargest commits by file count:" git whatchanged --name-only | awk ' /^commit/ {if (count>0) print commit, count; commit=$2; count=0} /^[A-Z]/ {count++} END {if (count>0) print commit, count} ' | sort -k2 -nr | head -5}
# Usagecommit_impact_analysisConfiguration and Best Practices:
Section titled “Configuration and Best Practices:”Git Configuration for Whatchanged:
Section titled “Git Configuration for Whatchanged:”# Configure default whatchanged behaviorgit config --global whatchanged.stat true # Show statistics by defaultgit config --global whatchanged.pretty oneline # Use oneline format
# Configure log formattinggit config --global format.pretty "format:%h %s %an %ar"
# Configure diff displaygit config --global whatchanged.showSignature true # Show signatures if availableSafe Whatchanged Operations:
Section titled “Safe Whatchanged Operations:”# Safe whatchanged with error handlingsafe_whatchanged() { local options="$1" local limit="${2:-10}"
echo "Running git whatchanged with options: $options (limit: $limit)"
# Check if we're in a git repository if ! git rev-parse --git-dir >/dev/null 2>&1; then echo "Error: Not in a Git repository" return 1 fi
# Run whatchanged with timeout protection timeout 30 git whatchanged $options -n "$limit" 2>/dev/null || { echo "Warning: whatchanged command timed out or failed" return 1 }}
# Usagesafe_whatchanged "--stat" 20Performance Optimization:
Section titled “Performance Optimization:”# Optimize whatchanged for large repositoriesfast_whatchanged() { local commits="$1"
echo "Fast whatchanged analysis for $commits commits..."
# Use --no-merges for cleaner output git whatchanged --no-merges --name-status -n "$commits"
# For very large repos, limit output if [ "$(git rev-list --count HEAD)" -gt 10000 ]; then echo "Large repository detected - consider using date ranges:" echo "git whatchanged --since='1 month ago'" fi}
# Memory-efficient analysismemory_efficient_analysis() { echo "Memory-efficient whatchanged analysis..."
# Process in batches local batch_size=100 local total_commits=$(git rev-list --count HEAD)
for ((start=0; start<total_commits; start+=batch_size)); do echo "Processing commits $start to $((start + batch_size))..." git whatchanged --name-only --skip="$start" -n"$batch_size" >/dev/null done}
# Usagefast_whatchanged 50Integration with Development Workflows:
Section titled “Integration with Development Workflows:”Code Review Preparation:
Section titled “Code Review Preparation:”# Prepare code review with whatchangedprepare_code_review() { local branch="${1:-feature-branch}" local base="${2:-main}"
echo "Preparing code review for $branch vs $base..."
# Create review summary cat > code-review-summary.md << EOF# Code Review Summary: $branch
## Files Changed$(git whatchanged --name-status "$base..$branch" | grep '^[AMD]' | wc -l) files modified
## Change Statistics$(git whatchanged --stat "$base..$branch" | tail -1)
## Detailed ChangesEOF
# Add detailed file changes git whatchanged --name-status "$base..$branch" >> code-review-summary.md
echo "Code review summary generated: code-review-summary.md"}
# Generate change impact reportchange_impact_report() { local since="${1:-1.week.ago}"
echo "Generating change impact report since $since..."
cat > change-impact-report.md << EOF# Change Impact Report
Generated: $(date)Period: Since $since
## Summary StatisticsEOF
# Calculate statistics total_commits=$(git whatchanged --since="$since" | grep '^commit' | wc -l) total_files=$(git whatchanged --name-only --since="$since" | grep -v '^commit' | wc -l) unique_files=$(git whatchanged --name-only --since="$since" | grep -v '^commit' | sort | uniq | wc -l)
cat >> change-impact-report.md << EOF- Total commits: $total_commits- Total file changes: $total_files- Unique files changed: $unique_files- Average changes per commit: $((total_files / total_commits))
## Most Changed Files$(git whatchanged --name-only --since="$since" | grep -v '^commit' | sort | uniq -c | sort -nr | head -10 | sed 's/^/ /')
## Recent Activity$(git whatchanged --oneline --since="$since" | head -10 | sed 's/^/ /')EOF
echo "Change impact report generated: change-impact-report.md"}
# Usageprepare_code_review "feature-x" "main"change_impact_report "2 weeks ago"CI/CD Integration:
Section titled “CI/CD Integration:”# Whatchanged in CI/CD pipelinesci_whatchanged_analysis() { echo "=== CI/CD Whatchanged Analysis ==="
# Analyze changes in PR/CI analyze_ci_changes() { echo "Analyzing changes in CI build..."
# Get changed files changed_files=$(git whatchanged --name-only "${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}..${CI_COMMIT_SHA}" | grep -v '^commit' | sort | uniq)
# Categorize changes source_files=$(echo "$changed_files" | grep -E '\.(js|ts|py|java|cpp|c)$' | wc -l) test_files=$(echo "$changed_files" | grep -E '(test|spec)\.' | wc -l) config_files=$(echo "$changed_files" | grep -E '\.(json|yml|yaml|xml|ini|conf)$' | wc -l) doc_files=$(echo "$changed_files" | grep -E '\.(md|txt|rst|adoc)$' | wc -l)
echo "Change Analysis:" echo " Source files: $source_files" echo " Test files: $test_files" echo " Config files: $config_files" echo " Documentation: $doc_files"
# Determine change type if [ "$source_files" -gt 10 ]; then echo "Large changeset detected - recommend thorough testing" elif [ "$test_files" -gt "$source_files" ]; then echo "Test-heavy changes detected" fi }
# Generate CI change report generate_ci_report() { echo "Generating CI change report..."
cat > ci-change-report.md << EOF# CI Change Report
Build: ${CI_BUILD_ID:-unknown}Branch: ${CI_COMMIT_REF_NAME:-unknown}Commit: ${CI_COMMIT_SHA:-unknown}
## Change Summary$(git whatchanged --stat "${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}..${CI_COMMIT_SHA}" | tail -1)
## Files Changed$(git whatchanged --name-status "${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}..${CI_COMMIT_SHA}" | grep '^[AMD]' | wc -l) files modified
## Detailed ChangesEOF
git whatchanged --name-status "${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}..${CI_COMMIT_SHA}" >> ci-change-report.md
echo "CI change report generated: ci-change-report.md" }
# Check for sensitive file changes check_sensitive_changes() { echo "Checking for sensitive file changes..."
sensitive_patterns="password|secret|key|token|credential"
sensitive_files=$(git whatchanged --name-only "${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}..${CI_COMMIT_SHA}" | grep -v '^commit' | grep -i "$sensitive_patterns")
if [ -n "$sensitive_files" ]; then echo "WARNING: Sensitive files detected:" echo "$sensitive_files" echo "Manual security review required" return 1 else echo "✓ No sensitive file changes detected" fi }
# Run CI analysis analyze_ci_changes echo generate_ci_report echo check_sensitive_changes}
# Usage in CIci_whatchanged_analysisRepository Analysis Tools:
Section titled “Repository Analysis Tools:”# Repository analysis using whatchangedrepository_whatchanged_analysis() { echo "=== Repository Whatchanged Analysis ==="
# Analyze development velocity analyze_development_velocity() { echo "Analyzing development velocity..."
# Commits per day for last month commits_per_day=$(git whatchanged --since="1 month ago" | grep '^commit' | wc -l) days_in_month=30 velocity=$((commits_per_day / days_in_month))
echo "Development velocity: $velocity commits/day"
# Files changed per day files_per_day=$(git whatchanged --name-only --since="1 month ago" | grep -v '^commit' | wc -l) avg_files=$((files_per_day / days_in_month))
echo "Average files changed per day: $avg_files" }
# Identify active contributors identify_active_contributors() { echo "Identifying active contributors..."
git whatchanged --since="3 months ago" | grep '^commit' | while read -r _ hash; do author=$(git show --no-patch --format="%an" "$hash") echo "$author" done | sort | uniq -c | sort -nr | head -10 | while read -r count author; do echo " $author: $count commits" done }
# Analyze file change hotspots analyze_change_hotspots() { echo "Analyzing file change hotspots..."
echo "Most frequently changed files (last 6 months):" git whatchanged --name-only --since="6 months ago" | grep -v '^commit' | sort | uniq -c | sort -nr | head -15 | while read -r count file; do echo " $file: $count changes" done
echo -e "\nChange frequency by directory:" git whatchanged --name-only --since="6 months ago" | grep -v '^commit' | xargs dirname 2>/dev/null | sort | uniq -c | sort -nr | head -10 | while read -r count dir; do echo " $dir: $count changes" done }
# Generate comprehensive analysis report generate_analysis_report() { echo "Generating comprehensive repository analysis..."
cat > repository-analysis-report.md << EOF# Repository Analysis Report
Generated: $(date)Repository: $(basename "$(pwd)")
## Development MetricsEOF
# Add metrics total_commits=$(git rev-list --count HEAD) active_period=$(git whatchanged | tail -1 | grep '^commit' | cut -d' ' -f2 | xargs git show --no-patch --format="%ar" || echo "unknown")
cat >> repository-analysis-report.md << EOF- Total commits: $total_commits- Repository age: $active_period- Active branches: $(git branch | wc -l)
## Recent Activity (Last 30 days)- Commits: $(git whatchanged --since="30 days ago" | grep '^commit' | wc -l)- Files changed: $(git whatchanged --name-only --since="30 days ago" | grep -v '^commit' | wc -l)- Contributors: $(git whatchanged --since="30 days ago" | grep '^commit' | while read -r _ hash; do git show --no-patch --format="%an" "$hash"; done | sort | uniq | wc -l)
## Top Contributors (Last 6 months)EOF
identify_active_contributors >> repository-analysis-report.md
cat >> repository-analysis-report.md << EOF
## File Change Hotspots (Last 6 months)EOF
git whatchanged --name-only --since="6 months ago" | grep -v '^commit' | sort | uniq -c | sort -nr | head -10 | sed 's/^/- /' >> repository-analysis-report.md
echo "Repository analysis report generated: repository-analysis-report.md" }
# Run comprehensive analysis analyze_development_velocity echo identify_active_contributors echo analyze_change_hotspots echo generate_analysis_report}
# Usagerepository_whatchanged_analysisTroubleshooting Common Issues:
Section titled “Troubleshooting Common Issues:”Performance Issues:
Section titled “Performance Issues:”# Troubleshoot whatchanged performancediagnose_whatchanged_performance() { echo "Diagnosing whatchanged performance issues..."
# Check repository size repo_size=$(du -sh .git 2>/dev/null | cut -f1) echo "Repository size: $repo_size"
commit_count=$(git rev-list --count HEAD) echo "Total commits: $commit_count"
# Performance recommendations if [ "$commit_count" -gt 100000 ]; then echo "Large repository detected. Performance tips:" echo " - Use date ranges: --since='1 month ago'" echo " - Limit output: -n 100" echo " - Use --no-merges to skip merge commits" echo " - Consider using git log --name-status for better performance" fi
# Test command performance echo "Testing whatchanged performance..." time git whatchanged --name-only -n 10 >/dev/null}
# Optimize whatchanged queriesoptimize_whatchanged_queries() { echo "Optimizing whatchanged queries..."
# Use specific paths to limit scope echo "Tip: Use path filtering for better performance" echo " git whatchanged -- src/ # Only source files" echo " git whatchanged --since='1 week ago' # Time-based filtering"
# Use --no-merges for cleaner output echo "Tip: Use --no-merges to exclude merge commits" echo " git whatchanged --no-merges --stat"
# Use oneline format for quick scanning echo "Tip: Use --oneline for compact output" echo " git whatchanged --oneline --name-status"}
# Usagediagnose_whatchanged_performanceoptimize_whatchanged_queriesOutput Interpretation Issues:
Section titled “Output Interpretation Issues:”# Troubleshoot output interpretationdebug_whatchanged_output() { echo "Debugging whatchanged output..."
# Show raw output for analysis echo "Sample whatchanged output:" git whatchanged -n 3 | head -20
echo -e "\nOutput explanation:" echo " 'commit <hash>' - Start of commit entry" echo " 'Author: <name>' - Commit author" echo " 'Date: <date>' - When commit was made" echo " 'A/M/D/R <file>' - File change status" echo " 'diff --git' - Start of patch output"
# Check for common issues if ! git whatchanged --name-status -n 1 >/dev/null 2>&1; then echo "Error: whatchanged command failed" echo "Possible causes:" echo " - Not in a Git repository" echo " - Repository corruption" echo " - Permission issues" fi}
# Validate whatchanged resultsvalidate_whatchanged_results() { echo "Validating whatchanged results..."
# Compare with git log whatchanged_count=$(git whatchanged | grep '^commit' | wc -l) log_count=$(git log --oneline | wc -l)
if [ "$whatchanged_count" -eq "$log_count" ]; then echo "✓ Commit counts match between whatchanged and log" else echo "⚠ Commit count mismatch: whatchanged=$whatchanged_count, log=$log_count" fi
# Check file change consistency whatchanged_files=$(git whatchanged --name-only | grep -v '^commit' | wc -l) log_files=$(git log --name-only | grep -v '^commit' | wc -l)
if [ "$whatchanged_files" -eq "$log_files" ]; then echo "✓ File change counts match" else echo "⚠ File change count mismatch: whatchanged=$whatchanged_files, log=$log_files" fi}
# Usagedebug_whatchanged_outputvalidate_whatchanged_resultsRepository State Issues:
Section titled “Repository State Issues:”# Handle repository state issueshandle_repo_state_issues() { echo "Handling repository state issues..."
# Check repository status if ! git status >/dev/null 2>&1; then echo "Error: Invalid Git repository" return 1 fi
# Check for uncommitted changes if [ -n "$(git status --porcelain)" ]; then echo "Warning: Uncommitted changes detected" echo "This may affect whatchanged output" fi
# Check current branch current_branch=$(git branch --show-current) echo "Current branch: $current_branch"
# Check if on detached HEAD if git status | grep -q "HEAD detached"; then echo "Warning: On detached HEAD" echo "whatchanged may show different results" fi
# Validate commit history latest_commit=$(git rev-parse HEAD 2>/dev/null) if [ -n "$latest_commit" ]; then echo "Latest commit: $latest_commit" else echo "Warning: No commits in repository" fi}
# Fix common repository issuesfix_common_repo_issues() { echo "Attempting to fix common repository issues..."
# Clean untracked files if safe if [ -n "$(git status --porcelain | grep '??')" ]; then echo "Untracked files detected" read -p "Remove untracked files? (y/N): " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then git clean -fd echo "✓ Untracked files removed" fi fi
# Reset to clean state if needed if [ -n "$(git status --porcelain)" ]; then echo "Uncommitted changes detected" read -p "Stash changes? (y/N): " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then git stash echo "✓ Changes stashed" fi fi
# Verify repository integrity if git fsck --full >/dev/null 2>&1; then echo "✓ Repository integrity verified" else echo "⚠ Repository integrity issues detected" echo "Consider: git fsck --full" fi}
# Usagehandle_repo_state_issuesfix_common_repo_issuesReal-World Usage Examples:
Section titled “Real-World Usage Examples:”Development Team Collaboration:
Section titled “Development Team Collaboration:”#!/bin/bash# Team collaboration with whatchanged
team_collaboration_workflow() { echo "=== Team Collaboration Workflow ==="
# Daily standup preparation prepare_daily_standup() { echo "Preparing daily standup report..."
cat > daily-standup-report.md << EOF# Daily Standup Report
Date: $(date)Team: Development Team
## Yesterday's ProgressEOF
# Show yesterday's commits git whatchanged --since="yesterday" --until="today" --pretty=format:"%an: %s" | grep -v '^commit' | while read -r line; do echo "- $line" >> daily-standup-report.md done
cat >> daily-standup-report.md << EOF
## Today's Plan- [ ] Task 1- [ ] Task 2- [ ] Task 3
## Blockers- None identifiedEOF
echo "Daily standup report generated: daily-standup-report.md" }
# Sprint review preparation prepare_sprint_review() { local sprint_start="$1"
echo "Preparing sprint review for sprint starting $sprint_start..."
cat > sprint-review-report.md << EOF# Sprint Review Report
Sprint Period: $sprint_start to $(date)Team: Development Team
## Sprint SummaryEOF
# Calculate sprint metrics total_commits=$(git whatchanged --since="$sprint_start" | grep '^commit' | wc -l) total_files=$(git whatchanged --name-only --since="$sprint_start" | grep -v '^commit' | wc -l) contributors=$(git whatchanged --since="$sprint_start" | grep '^commit' | while read -r _ hash; do git show --no-patch --format="%an" "$hash"; done | sort | uniq | wc -l)
cat >> sprint-review-report.md << EOF- Total commits: $total_commits- Files changed: $total_files- Contributors: $contributors- Average commits per day: $((total_commits / 14)) (assuming 2-week sprint)
## Key ChangesEOF
# Show major changes git whatchanged --since="$sprint_start" --name-status | grep '^[AMD]' | cut -f2 | sort | uniq -c | sort -nr | head -10 | sed 's/^/- /' >> sprint-review-report.md
cat >> sprint-review-report.md << EOF
## Lessons Learned- What went well- What could be improved- Action items for next sprintEOF
echo "Sprint review report generated: sprint-review-report.md" }
# Code review assignment assign_code_reviews() { echo "Assigning code reviews based on whatchanged analysis..."
# Get recent commits by author declare -A author_commits
git whatchanged --since="1 week ago" | grep '^commit' | while read -r _ hash; do author=$(git show --no-patch --format="%an" "$hash") author_commits["$author"]=$((author_commits["$author"] + 1)) done
echo "Code review assignments for this week:" for author in "${!author_commits[@]}"; do commits=${author_commits[$author]} echo " $author: $commits commits"
# Suggest reviewer based on commit volume if [ "$commits" -gt 10 ]; then echo " → High activity - assign senior reviewer" elif [ "$commits" -gt 5 ]; then echo " → Medium activity - assign peer reviewer" else echo " → Low activity - assign junior reviewer" fi done }
# Interactive team workflow echo "Team Collaboration Workflow Options:" echo "1. Prepare daily standup" echo "2. Prepare sprint review" echo "3. Assign code reviews"
read -p "Select option (1-3): " option
case "$option" in 1) prepare_daily_standup ;; 2) read -p "Sprint start date (YYYY-MM-DD): " sprint_date prepare_sprint_review "$sprint_date" ;; 3) assign_code_reviews ;; esac}
team_collaboration_workflowQuality Assurance and Testing:
Section titled “Quality Assurance and Testing:”# QA testing with whatchanged analysisqa_whatchanged_analysis() { echo "=== QA Whatchanged Analysis ==="
# Analyze test coverage changes analyze_test_coverage() { echo "Analyzing test coverage changes..."
# Get test files changed test_files_changed=$(git whatchanged --name-only --since="1 week ago" | grep -v '^commit' | grep -E '(test|spec)\.' | wc -l)
# Get source files changed source_files_changed=$(git whatchanged --name-only --since="1 week ago" | grep -v '^commit' | grep -E '\.(js|ts|py|java|cpp|c)$' | wc -l)
echo "Test coverage analysis (last week):" echo " Source files changed: $source_files_changed" echo " Test files changed: $test_files_changed"
if [ "$source_files_changed" -gt 0 ]; then coverage_ratio=$((test_files_changed * 100 / source_files_changed)) echo " Test coverage ratio: ${coverage_ratio}%"
if [ "$coverage_ratio" -lt 50 ]; then echo " ⚠ Low test coverage - recommend additional tests" elif [ "$coverage_ratio" -gt 150 ]; then echo " ✓ Good test coverage - tests exceed changes" fi fi }
# Identify risky changes identify_risky_changes() { echo "Identifying potentially risky changes..."
# Files that might need extra testing risky_patterns="auth|security|payment|database|config"
risky_files=$(git whatchanged --name-only --since="1 week ago" | grep -v '^commit' | grep -i "$risky_patterns")
if [ -n "$risky_files" ]; then echo "Risky files changed (require extra testing):" echo "$risky_files" | sed 's/^/- /'
# Suggest testing approaches if echo "$risky_files" | grep -qi "auth\|security"; then echo "→ Security testing required" fi
if echo "$risky_files" | grep -qi "payment"; then echo "→ Payment flow testing required" fi
if echo "$risky_files" | grep -qi "database"; then echo "→ Database migration testing required" fi else echo "✓ No high-risk changes detected" fi }
# Generate QA testing report generate_qa_report() { echo "Generating QA testing report..."
cat > qa-testing-report.md << EOF# QA Testing Report
Generated: $(date)Test Period: Last 7 days
## Change SummaryEOF
# Add change summary total_changes=$(git whatchanged --name-only --since="7 days ago" | grep -v '^commit' | wc -l) unique_files=$(git whatchanged --name-only --since="7 days ago" | grep -v '^commit' | sort | uniq | wc -l)
cat >> qa-testing-report.md << EOF- Total file changes: $total_changes- Unique files changed: $unique_files- Average changes per day: $((total_changes / 7))
## Files Requiring TestingEOF
# Categorize files by testing needs git whatchanged --name-only --since="7 days ago" | grep -v '^commit' | sort | uniq | while read -r file; do if [[ "$file" =~ \.(js|ts|py|java)$ ]]; then echo "- [ ] $file (Unit tests required)" >> qa-testing-report.md elif [[ "$file" =~ (test|spec)\. ]]; then echo "- [ ] $file (Test file - verify functionality)" >> qa-testing-report.md elif [[ "$file" =~ \.(html|css)$ ]]; then echo "- [ ] $file (UI testing required)" >> qa-testing-report.md else echo "- [ ] $file (General testing required)" >> qa-testing-report.md fi done
cat >> qa-testing-report.md << EOF
## Testing Checklist- [ ] Unit tests pass- [ ] Integration tests pass- [ ] End-to-end tests pass- [ ] Performance tests pass- [ ] Security tests pass- [ ] Cross-browser testing complete
## Test Results- [ ] All tests passing- [ ] No regressions detected- [ ] Performance within acceptable limitsEOF
echo "QA testing report generated: qa-testing-report.md" }
# Run QA analysis analyze_test_coverage echo identify_risky_changes echo generate_qa_report}
# Usageqa_whatchanged_analysisRelease Management:
Section titled “Release Management:”# Release management with whatchangedrelease_management_workflow() { echo "=== Release Management Workflow ==="
# Prepare release notes prepare_release_notes() { local version="$1" local previous_tag="$2"
echo "Preparing release notes for version $version..."
cat > RELEASE-NOTES-$version.md << EOF# Release Notes - Version $version
Released: $(date)Previous Version: $previous_tag
## OverviewBrief description of this release.
## ChangesEOF
# Categorize changes echo "### New Features" >> RELEASE-NOTES-$version.md git whatchanged --grep="feat:" --pretty=format:"- %s" "$previous_tag..HEAD" 2>/dev/null | head -10 >> RELEASE-NOTES-$version.md
echo -e "\n### Bug Fixes" >> RELEASE-NOTES-$version.md git whatchanged --grep="fix:" --pretty=format:"- %s" "$previous_tag..HEAD" 2>/dev/null | head -10 >> RELEASE-NOTES-$version.md
echo -e "\n### Other Changes" >> RELEASE-NOTES-$version.md git whatchanged --grep="^(?!feat:|fix:)" --pretty=format:"- %s" "$previous_tag..HEAD" 2>/dev/null | grep -v "^commit" | head -10 >> RELEASE-NOTES-$version.md
cat >> RELEASE-NOTES-$version.md << EOF
## Files Changed$(git whatchanged --name-status "$previous_tag..HEAD" | grep '^[AMD]' | wc -l) files modified
## Contributors$(git whatchanged "$previous_tag..HEAD" | grep '^commit' | while read -r _ hash; do git show --no-patch --format="%an" "$hash"; done | sort | uniq | tr '\n' ', ' | sed 's/, $//')
## Upgrade Instructions1. Backup your data2. Stop the application3. Apply the update4. Restart the application5. Verify functionalityEOF
echo "Release notes generated: RELEASE-NOTES-$version.md" }
# Validate release readiness validate_release_readiness() { local version="$1"
echo "Validating release readiness for $version..."
# Check version format if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "❌ Invalid version format: $version" return 1 fi
# Check if tag already exists if git tag | grep -q "^$version$"; then echo "❌ Tag $version already exists" return 1 fi
# Check for uncommitted changes if [ -n "$(git status --porcelain)" ]; then echo "❌ Uncommitted changes detected" return 1 fi
# Check branch status current_branch=$(git branch --show-current) if [ "$current_branch" != "main" ] && [ "$current_branch" != "master" ]; then echo "⚠ Not on main/master branch: $current_branch" fi
# Validate recent changes recent_commits=$(git whatchanged -n 5 | grep '^commit' | wc -l) if [ "$recent_commits" -eq 0 ]; then echo "⚠ No recent commits found" fi
echo "✅ Release validation passed" }
# Create release tag create_release_tag() { local version="$1" local message="$2"
echo "Creating release tag $version..."
# Create annotated tag git tag -a "$version" -m "Release $version
$message
Files changed: $(git whatchanged --name-only HEAD~1..HEAD | grep -v '^commit' | wc -l)Contributors: $(git whatchanged HEAD~1..HEAD | grep '^commit' | while read -r _ hash; do git show --no-patch --format="%an" "$hash"; done | sort | uniq | wc -l)"
# Verify tag creation if git verify-tag "$version" >/dev/null 2>&1; then echo "✅ Release tag $version created successfully" git tag -l "$version" else echo "❌ Failed to create release tag" return 1 fi }
# Interactive release management echo "Release Management Workflow Options:" echo "1. Prepare release notes" echo "2. Validate release readiness" echo "3. Create release tag"
read -p "Select option (1-3): " option
case "$option" in 1) read -p "Version: " version read -p "Previous tag: " prev_tag prepare_release_notes "$version" "$prev_tag" ;; 2) read -p "Version to validate: " version validate_release_readiness "$version" ;; 3) read -p "Version: " version read -p "Release message: " message create_release_tag "$version" "$message" ;; esac}
# Usagerelease_management_workflow