Skip to content

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.

Terminal window
git whatchanged [options] [--] [path...]
OptionDescription
-p, --patchShow patch (diff) for each commit
--statShow statistics about files changed
--name-onlyShow only names of changed files
--name-statusShow names and status of changed files
--pretty=<format>Pretty-print commit messages
--onelineShorthand for --pretty=oneline --abbrev-commit
--graphDraw commit history graph
--decorateShow ref names of commits
--followFollow 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
--reverseShow commits in reverse order
ParameterDescription
<path>Show only commits that affect specified paths
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 changes
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 conflicts
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 statistics
Terminal window
# Show last 10 commits with changed files
git whatchanged -10
# Show commits with file names only
git whatchanged --name-only -5
# Show commits with file status
git whatchanged --name-status -5
Terminal window
# Show commit statistics
git whatchanged --stat -10
# Show detailed patch output
git whatchanged -p -3
# Show oneline format with changes
git whatchanged --oneline --name-status -10
Terminal window
# Show changes to specific file
git whatchanged -- src/main.js
# Show changes to directory
git whatchanged -- src/components/
# Show changes to multiple paths
git whatchanged -- src/ tests/
Terminal window
# Show changes from last week
git whatchanged --since="1 week ago"
# Show changes between dates
git whatchanged --since="2024-01-01" --until="2024-01-31"
# Show today's changes
git whatchanged --since="midnight"
Terminal window
# Show changes by specific author
git whatchanged --author="John Doe"
# Show commits containing specific text
git whatchanged --grep="bug fix"
# Combine filters
git whatchanged --author="Jane" --grep="feature" --since="1 month ago"
Terminal window
# Analyze file change patterns
analyze_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 files
most_changed_files() {
echo "Most frequently changed files:"
git whatchanged --name-only -100 | grep -v '^commit' | sort | uniq -c | sort -nr | head -10
}
# Usage
analyze_file_changes
echo
most_changed_files
Terminal window
# Analyze commit impact
commit_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
}
# Usage
commit_impact_analysis
Terminal window
# Configure default whatchanged behavior
git config --global whatchanged.stat true # Show statistics by default
git config --global whatchanged.pretty oneline # Use oneline format
# Configure log formatting
git config --global format.pretty "format:%h %s %an %ar"
# Configure diff display
git config --global whatchanged.showSignature true # Show signatures if available
Terminal window
# Safe whatchanged with error handling
safe_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
}
}
# Usage
safe_whatchanged "--stat" 20
Terminal window
# Optimize whatchanged for large repositories
fast_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 analysis
memory_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
}
# Usage
fast_whatchanged 50
Terminal window
# Prepare code review with whatchanged
prepare_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 Changes
EOF
# 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 report
change_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 Statistics
EOF
# 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"
}
# Usage
prepare_code_review "feature-x" "main"
change_impact_report "2 weeks ago"
Terminal window
# Whatchanged in CI/CD pipelines
ci_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 Changes
EOF
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 CI
ci_whatchanged_analysis
Terminal window
# Repository analysis using whatchanged
repository_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 Metrics
EOF
# 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
}
# Usage
repository_whatchanged_analysis
Terminal window
# Troubleshoot whatchanged performance
diagnose_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 queries
optimize_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"
}
# Usage
diagnose_whatchanged_performance
optimize_whatchanged_queries
Terminal window
# Troubleshoot output interpretation
debug_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 results
validate_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
}
# Usage
debug_whatchanged_output
validate_whatchanged_results
Terminal window
# Handle repository state issues
handle_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 issues
fix_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
}
# Usage
handle_repo_state_issues
fix_common_repo_issues
#!/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 Progress
EOF
# 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 identified
EOF
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 Summary
EOF
# 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 Changes
EOF
# 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 sprint
EOF
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_workflow
Terminal window
# QA testing with whatchanged analysis
qa_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 Summary
EOF
# 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 Testing
EOF
# 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 limits
EOF
echo "QA testing report generated: qa-testing-report.md"
}
# Run QA analysis
analyze_test_coverage
echo
identify_risky_changes
echo
generate_qa_report
}
# Usage
qa_whatchanged_analysis
Terminal window
# Release management with whatchanged
release_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
## Overview
Brief description of this release.
## Changes
EOF
# 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 Instructions
1. Backup your data
2. Stop the application
3. Apply the update
4. Restart the application
5. Verify functionality
EOF
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
}
# Usage
release_management_workflow