Created
November 7, 2025 12:00
-
-
Save Konamiman/4a0073c540361aff7d48aadb41afab60 to your computer and use it in GitHub Desktop.
Count git changed and deleted lines in the working tree or in the staged files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # chgcount.sh - Count lines added/modified and deleted in git diff | |
| # | |
| # Usage: chgcount.sh [OPTIONS] | |
| # | |
| # Options: | |
| # -p, --pattern PATTERN File pattern to check (default: all files) | |
| # Use **/ prefix for recursive matching in subdirectories | |
| # -f, --files FILES Explicit space-separated list of files to check | |
| # -s, --staged Look into staged files (default: unstaged) | |
| # -b, --branch BRANCH Compare against branch (default: current working tree) | |
| # -d, --details Show detailed per-file statistics | |
| # -h, --help Show this help message | |
| # | |
| # Pattern Examples: | |
| # "*.php" Matches PHP files in current directory only | |
| # "**/*.php" Matches PHP files recursively in all subdirectories | |
| # "**/Rest*.php" Matches Rest*.php files anywhere in the tree | |
| # "src/**/*.php" Matches PHP files only under src/ directory | |
| # | |
| # Usage Examples: | |
| # chgcount.sh # Count unstaged changes | |
| # chgcount.sh -s # Count staged changes | |
| # chgcount.sh -p "**/*.php" # Count all PHP files recursively | |
| # chgcount.sh -p "**/Rest*.php" # Count Rest*.php files anywhere | |
| # chgcount.sh -f "file1.php file2.php" # Count specific files only | |
| # chgcount.sh -b trunk # Compare current branch against trunk | |
| # chgcount.sh -b trunk -p "**/*.php" -d # PHP files vs trunk with details | |
| set -e | |
| # Default values | |
| PATTERN="" | |
| FILE_LIST="" | |
| STAGED=false | |
| BRANCH="" | |
| DETAILS=false | |
| # Parse arguments | |
| while [[ $# -gt 0 ]]; do | |
| case $1 in | |
| -p|--pattern) | |
| PATTERN="$2" | |
| shift 2 | |
| ;; | |
| -f|--files) | |
| FILE_LIST="$2" | |
| shift 2 | |
| ;; | |
| -s|--staged) | |
| STAGED=true | |
| shift | |
| ;; | |
| -b|--branch) | |
| BRANCH="$2" | |
| shift 2 | |
| ;; | |
| -d|--details) | |
| DETAILS=true | |
| shift | |
| ;; | |
| -h|--help) | |
| sed -n '/^# chgcount.sh/,/^$/p' "$0" | sed 's/^# \?//' | sed '/^$/d' | |
| exit 0 | |
| ;; | |
| *) | |
| echo "Unknown option: $1" | |
| echo "Use -h or --help for usage information" | |
| exit 1 | |
| ;; | |
| esac | |
| done | |
| # Check if we're in a git repository | |
| if ! git rev-parse --git-dir > /dev/null 2>&1; then | |
| echo "Error: Not a git repository" | |
| exit 1 | |
| fi | |
| # Validate that pattern and files are not both specified | |
| if [ -n "$PATTERN" ] && [ -n "$FILE_LIST" ]; then | |
| echo "Error: Cannot use both --pattern and --files options together" | |
| exit 1 | |
| fi | |
| # Build git diff command | |
| GIT_CMD="git diff --numstat" | |
| if [ "$STAGED" = true ]; then | |
| GIT_CMD="$GIT_CMD --staged" | |
| fi | |
| if [ -n "$BRANCH" ]; then | |
| GIT_CMD="$GIT_CMD $BRANCH" | |
| fi | |
| if [ -n "$PATTERN" ]; then | |
| GIT_CMD="$GIT_CMD -- $PATTERN" | |
| elif [ -n "$FILE_LIST" ]; then | |
| GIT_CMD="$GIT_CMD -- $FILE_LIST" | |
| fi | |
| # Get the diff stats | |
| DIFF_OUTPUT=$($GIT_CMD) | |
| if [ -z "$DIFF_OUTPUT" ]; then | |
| if [ "$STAGED" = true ]; then | |
| echo "No staged changes found." | |
| else | |
| echo "No changes found in working tree." | |
| fi | |
| echo "Run with -h for more options" | |
| exit 0 | |
| fi | |
| # Parse the output and sum up the changes | |
| ADDED=0 | |
| DELETED=0 | |
| FILES=0 | |
| declare -a FILE_DETAILS | |
| while IFS=$'\t' read -r add del file; do | |
| # Skip binary files (marked with -) | |
| if [ "$add" = "-" ] || [ "$del" = "-" ]; then | |
| continue | |
| fi | |
| ADDED=$((ADDED + add)) | |
| DELETED=$((DELETED + del)) | |
| FILES=$((FILES + 1)) | |
| # Store details for later if needed | |
| if [ "$DETAILS" = true ]; then | |
| FILE_DETAILS+=("$add|$del|$file") | |
| fi | |
| done <<< "$DIFF_OUTPUT" | |
| # Check if run without arguments | |
| NO_ARGS=false | |
| if [ "$STAGED" = false ] && [ -z "$BRANCH" ] && [ -z "$PATTERN" ] && [ -z "$FILE_LIST" ]; then | |
| NO_ARGS=true | |
| fi | |
| # Print results | |
| echo "========================" | |
| echo "Git Diff Statistics" | |
| echo "========================" | |
| if [ "$STAGED" = true ]; then | |
| echo "Mode: Staged changes" | |
| else | |
| echo "Mode: Unstaged changes" | |
| fi | |
| CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) | |
| if [ -n "$BRANCH" ]; then | |
| if [ "$STAGED" = true ]; then | |
| echo "Comparing: staged changes in $CURRENT_BRANCH vs $BRANCH" | |
| else | |
| echo "Comparing: working tree changes in $CURRENT_BRANCH vs $BRANCH" | |
| fi | |
| else | |
| if [ "$STAGED" = true ]; then | |
| echo "Comparing: staged changes vs $CURRENT_BRANCH" | |
| else | |
| echo "Comparing: working tree changes vs $CURRENT_BRANCH" | |
| fi | |
| fi | |
| if [ -n "$PATTERN" ]; then | |
| echo "Pattern: $PATTERN" | |
| elif [ -n "$FILE_LIST" ]; then | |
| echo "Files: $FILE_LIST" | |
| fi | |
| echo "------------------------" | |
| echo "Files changed: $FILES" | |
| echo "Lines added/modified: $ADDED" | |
| echo "Lines deleted: $DELETED" | |
| echo "Net change: $((ADDED - DELETED))" | |
| echo "========================" | |
| # Show detailed breakdown if requested | |
| if [ "$DETAILS" = true ] && [ ${#FILE_DETAILS[@]} -gt 0 ]; then | |
| echo "" | |
| echo "Per-file breakdown:" | |
| echo "------------------------" | |
| printf "%-10s %-10s %-10s %s\n" "Added" "Deleted" "Net" "File" | |
| printf "%-10s %-10s %-10s %s\n" "------" "-------" "---" "----" | |
| for entry in "${FILE_DETAILS[@]}"; do | |
| IFS='|' read -r add del file <<< "$entry" | |
| net=$((add - del)) | |
| printf "%-10s %-10s %-10s %s\n" "$add" "$del" "$net" "$file" | |
| done | |
| echo "========================" | |
| fi | |
| if [ "$NO_ARGS" = true ]; then | |
| echo "" | |
| echo "Run with -h for more options" | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment