Skip to content

Instantly share code, notes, and snippets.

@antonlvovych
Created June 17, 2025 17:20
Show Gist options
  • Save antonlvovych/190ce978fbf95e4671c18e2205173d8d to your computer and use it in GitHub Desktop.
Save antonlvovych/190ce978fbf95e4671c18e2205173d8d to your computer and use it in GitHub Desktop.
Git Insights Script - Enhanced version with auto-generated file exclusions
#!/bin/sh
# Git Insights Script - Enhanced version with auto-generated file exclusions
# Usage: sh git-insights.sh [start_date] [end_date]
# Example: sh git-insights.sh 2024-01-01 2024-12-31
function days_between {
local start_timestamp="$1"
local end_timestamp="$2"
local seconds_diff=$((end_timestamp - start_timestamp))
local days_diff=$((seconds_diff / 86400)) # 86400 seconds in a day
echo "$days_diff"
}
# Use git to filter files (respects .gitignore automatically)
# No manual exclude patterns needed - git ls-files only shows tracked files
# Get project date range
first_commit_hash=$(git rev-list --max-parents=0 HEAD)
last_commit_hash=$(git rev-parse HEAD)
start_timestamp=$(git log -n 1 --pretty=format:%ct "$first_commit_hash")
end_timestamp=$(git log -n 1 --pretty=format:%ct "$last_commit_hash")
days_diff=$(days_between "$start_timestamp" "$end_timestamp")
first_commit_date=$(git log -n 1 --pretty=format:%ci --date=format-local:"%Y-%m-%d" "$first_commit_hash")
last_commit_date=$(git log -n 1 --pretty=format:%ci --date=format-local:"%Y-%m-%d" "$last_commit_hash")
# Parse command line arguments
start_date="$1"
end_date="$2"
if [ -n "$start_date" ]; then
stats_start_timestamp=$(date -jf "%Y-%m-%d" "$start_date" "+%s")
stats_start_date=$(date -jf "%s" "$stats_start_timestamp" "+%Y-%m-%d")
stats_start_date_str=$stats_start_date
else
stats_start_timestamp=$start_timestamp
stats_start_date=$(date -jf "%s" "$stats_start_timestamp" "+%Y-%m-%d")
stats_start_date_str=$stats_start_date
fi
if [ -n "$end_date" ]; then
stats_end_timestamp=$(date -jf "%Y-%m-%d" "$end_date" "+%s")
stats_end_date=$(date -jf "%s" "$stats_end_timestamp" "+%Y-%m-%d")
stats_end_date_str=$stats_end_date
else
stats_end_timestamp=$(date +%s)
stats_end_date=$(date -jf "%s" "$stats_end_timestamp" "+%Y-%m-%d")
stats_end_date_str=$stats_end_date
fi
echo "πŸ” Git Repository Insights"
echo "=========================="
echo "πŸ“… Analysis Period: $stats_start_date_str to $stats_end_date_str"
echo ""
echo "πŸ“Š Code Statistics (Git Tracked Files)"
echo "=================================================="
# Test files and test cases
TEST_FILES=$(git ls-files | grep -E '\.(test|spec)\.(js|ts)$|/__tests__/|/tests?/' | wc -l | tr -d ' ')
TEST_LINES=$(git ls-files | grep -E '\.(test|spec)\.(js|ts)$|/__tests__/|/tests?/' | xargs cat 2>/dev/null | wc -l | tr -d ' ')
TEST_CASES=$(git ls-files | grep -E '\.(test|spec)\.(js|ts)$|/__tests__/|/tests?/' | xargs grep -E "^\s*(test|it)\s*\(" 2>/dev/null | wc -l | tr -d ' ')
# Real code files (excluding docs and data files, including tests)
CODE_FILES=$(git ls-files | grep -vE '\.md$|^data/|^logs/' | wc -l | tr -d ' ')
CODE_LINES=$(git ls-files | grep -vE '\.md$|^data/|^logs/' | xargs cat 2>/dev/null | wc -l | tr -d ' ')
# Documentation files
DOC_FILES=$(git ls-files | grep -E '\.md$' | wc -l | tr -d ' ')
DOC_LINES=$(git ls-files | grep -E '\.md$' | xargs cat 2>/dev/null | wc -l | tr -d ' ')
# Total
TOTAL_FILES=$(git ls-files | wc -l | tr -d ' ')
TOTAL_LINES=$(git ls-files | xargs cat 2>/dev/null | wc -l | tr -d ' ')
echo "β€’ Code files (inc. tests): $CODE_FILES ($CODE_LINES lines)"
echo "β€’ Test files breakdown: $TEST_FILES ($TEST_LINES lines, $TEST_CASES test cases)"
echo "β€’ Documentation files: $DOC_FILES ($DOC_LINES lines)"
echo "β€’ Total files tracked: $TOTAL_FILES ($TOTAL_LINES lines)"
echo ""
echo "πŸ“ˆ Change Statistics (All Files)"
echo "================================"
git log --shortstat --no-merges --since=$stats_start_date_str --until=$stats_end_date_str | grep -E "fil(e|es) changed" | awk '{files+=$1; inserted+=$4; deleted+=$6; delta+=$4-$6; ratio=(deleted>0?deleted/inserted:0)} END {printf "β€’ Files changed: %s\nβ€’ Lines added: %s\nβ€’ Lines deleted: %s\nβ€’ Net lines: %s\nβ€’ Add/Del ratio: 1:%.2f\n", files, inserted, deleted, delta, ratio }'
echo ""
echo "πŸ“ˆ Change Statistics (Excluding Data Files)"
echo "==========================================="
git log --numstat --no-merges --since=$stats_start_date_str --until=$stats_end_date_str | grep -E '^[0-9-]+\s+[0-9-]+' | grep -vE '\s+(data/|logs/)' | awk '{if($1 != "-" && $2 != "-") {inserted+=$1; deleted+=$2}} END {printf "β€’ Lines added (code): %s\nβ€’ Lines deleted (code): %s\nβ€’ Net lines (code): %s\n", inserted+0, deleted+0, inserted-deleted}'
echo ""
echo "πŸ‘₯ Contributors"
echo "==============="
git shortlog -sn --no-merges --since=$stats_start_date_str --until=$stats_end_date_str | while read commits author; do
echo "β€’ $author: $commits commits"
done
echo ""
echo "⏰ Peak Activity Hours (All Commits in Period)"
echo "=============================================="
git log --format="%ad" --date=format:"%H" --since=$stats_start_date_str --until=$stats_end_date_str | sort | uniq -c | sort -nr | head -10 | while read count hour; do
echo "β€’ ${hour}:00 - $count commits"
done
echo ""
echo "πŸ“ Most Active Code Files (Including Tests)"
echo "==========================================="
git log --name-only --pretty=format: --since=$stats_start_date_str --until=$stats_end_date_str | grep -v '^$' | grep -vE '\.md$|^data/|^logs/' | sort | uniq -c | sort -nr | head -10 | while read count file; do
echo "β€’ $file ($count changes)"
done
echo ""
echo "πŸ§ͺ Most Active Test Files"
echo "========================="
git log --name-only --pretty=format: --since=$stats_start_date_str --until=$stats_end_date_str | grep -v '^$' | grep -E '\.(test|spec)\.(js|ts)$|/__tests__/|/tests?/' | sort | uniq -c | sort -nr | head -5 | while read count file; do
echo "β€’ $file ($count changes)"
done
echo ""
echo "πŸ“ Most Active Documentation Files"
echo "=================================="
git log --name-only --pretty=format: --since=$stats_start_date_str --until=$stats_end_date_str | grep -v '^$' | grep -E '\.md$' | sort | uniq -c | sort -nr | head -10 | while read count file; do
echo "β€’ $file ($count changes)"
done
echo ""
echo "🏷️ Recent Commits"
echo "=================="
git log --oneline -10 --since=$stats_start_date_str --until=$stats_end_date_str --pretty=format:"β€’ %s (%an)" | head -10
echo ""
echo "πŸ“… Project Timeline"
echo "=================="
echo "β€’ First commit: $first_commit_date"
echo "β€’ Latest commit: $last_commit_date"
echo "β€’ Project age: $days_diff days"
# Calculate activity metrics
COMMITS_IN_PERIOD=$(git rev-list --count --since=$stats_start_date_str --until=$stats_end_date_str HEAD)
PERIOD_DAYS=$(days_between "$stats_start_timestamp" "$stats_end_timestamp")
if [ "$PERIOD_DAYS" -gt 0 ]; then
COMMITS_PER_DAY=$(echo "scale=1; $COMMITS_IN_PERIOD / $PERIOD_DAYS" | bc -l 2>/dev/null || echo "N/A")
else
COMMITS_PER_DAY="N/A"
fi
echo ""
echo "πŸš€ Summary for Analysis Period"
echo "============================="
echo "β€’ $COMMITS_IN_PERIOD commits across $PERIOD_DAYS days"
echo "β€’ Average commits/day: $COMMITS_PER_DAY"
echo "β€’ Code lines (inc. tests): $CODE_LINES"
echo "β€’ Documentation lines: $DOC_LINES"
# Get net lines for period and daily average (excluding data files)
NET_LINES=$(git log --numstat --no-merges --since=$stats_start_date_str --until=$stats_end_date_str | grep -E '^[0-9-]+\s+[0-9-]+' | grep -vE '\s+(data/|logs/)' | awk '{if($1 != "-" && $2 != "-") {delta+=$1-$2}} END {print delta+0}')
if [ "$PERIOD_DAYS" -gt 0 ] && [ -n "$NET_LINES" ]; then
DAILY_LINES=$(echo "scale=0; $NET_LINES / $PERIOD_DAYS" | bc -l 2>/dev/null || echo "N/A")
echo "β€’ Net lines added (code): $NET_LINES"
echo "β€’ Average lines/day (code): $DAILY_LINES"
fi
# Peak hours summary
PEAK_HOURS=$(git log --format="%ad" --date=format:"%H" --since=$stats_start_date_str --until=$stats_end_date_str | sort | uniq -c | sort -nr | head -3 | awk '{printf "%s:00, ", $2}' | sed 's/, $//')
if [ -n "$PEAK_HOURS" ]; then
echo "β€’ Peak hours: $PEAK_HOURS"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment