From 3f9b2d3d7c571caf9b3ae0a1fb297422af5df91c Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 1 Jun 2025 18:51:03 +1200 Subject: [PATCH] 'Generic Commit' --- whatsdirty/whatsdirty.sh | 141 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100755 whatsdirty/whatsdirty.sh diff --git a/whatsdirty/whatsdirty.sh b/whatsdirty/whatsdirty.sh new file mode 100755 index 0000000..1b8bed8 --- /dev/null +++ b/whatsdirty/whatsdirty.sh @@ -0,0 +1,141 @@ +#!/bin/bash + +# iterate through all subfolders in the current directory (or $1 if provided), +# and check: +# is it a git rep? +# if so is it clean (nothing to commit)? +# +# for each git repo print the name of the repo, the datestamp of the last commit, +# the nubmer of changes since then, and whether it's clean or not. + +# if no argument is provided, use the current directory +DIR="${1:-.}" + +# make directory canonical +DIR=$(cd "$DIR" 2>/dev/null && pwd) || { echo "Error: Directory '$1' not found"; exit 1; } + +# Color codes +RED='\033[0;31m' +NC='\033[0m' # No Color + +# Temporary file to store repository data +TEMP_FILE=$(mktemp) +# shellcheck disable=SC2064 +trap "rm -f $TEMP_FILE" EXIT + +# iterate through all subfolders in DIR +for folder in "$DIR"/*; do + # Skip if not a directory + [ ! -d "$folder" ] && continue + + # Check if it's a git repository + if [ -d "$folder/.git" ]; then + # Get the folder name + repo_name=$(basename "$folder") + + # Change to the repository directory + cd "$folder" || continue + + # Get the last commit timestamp in seconds since epoch + last_commit_timestamp=$(git log -1 --format="%ct" 2>/dev/null) + + if [ -n "$last_commit_timestamp" ]; then + # Get current timestamp + current_timestamp=$(date +%s) + + # Calculate difference in seconds + diff_seconds=$((current_timestamp - last_commit_timestamp)) + + # Convert to hours with decimal precision + # Using bc for floating point arithmetic + hours_ago=$(echo "scale=1; $diff_seconds / 3600" | bc) + + # Ensure leading zero for values less than 1 + if [[ $hours_ago =~ ^\. ]]; then + hours_ago="0$hours_ago" + fi + + # Format the hours number and "hours" label separately + hours_num="$hours_ago" + hours_label="hours" + # Combine with right-justified formatting + hours_formatted=$(printf "%8s %-6s" "$hours_num" "$hours_label") + else + hours_num="999999" # Large number for sorting + hours_label="commits" + hours_formatted=$(printf "%8s %-7s" "No" "$hours_label") + fi + + # Count uncommitted changes (staged and unstaged) + # Count modified, deleted, and untracked files + staged_changes=$(git diff --cached --numstat 2>/dev/null | wc -l) + unstaged_changes=$(git diff --numstat 2>/dev/null | wc -l) + untracked_files=$(git ls-files --others --exclude-standard 2>/dev/null | wc -l) + total_changes=$((staged_changes + unstaged_changes + untracked_files)) + + # Store repo data with status prefix (D for dirty, C for clean) + if [ $total_changes -eq 0 ]; then + echo "C|${hours_num}|${total_changes}|${repo_name}|${hours_formatted}" >> "$TEMP_FILE" + else + # For dirty repos, collect the list of changed files + changed_files="" + + # Get staged files + staged_files=$(git diff --cached --name-only 2>/dev/null) + if [ -n "$staged_files" ]; then + while IFS= read -r file; do + changed_files="${changed_files} [staged] $file\n" + done <<< "$staged_files" + fi + + # Get unstaged modified files + unstaged_files=$(git diff --name-only 2>/dev/null) + if [ -n "$unstaged_files" ]; then + while IFS= read -r file; do + changed_files="${changed_files} [modified] $file\n" + done <<< "$unstaged_files" + fi + + # Get untracked files + untracked=$(git ls-files --others --exclude-standard 2>/dev/null) + if [ -n "$untracked" ]; then + while IFS= read -r file; do + changed_files="${changed_files} [untracked] $file\n" + done <<< "$untracked" + fi + + # Remove trailing newline + changed_files=$(echo -e "$changed_files" | sed '$ d') + + # Store with a special delimiter (|||) to separate file list + echo "D|${hours_num}|${total_changes}|${repo_name}|${hours_formatted}|||${changed_files}" >> "$TEMP_FILE" + fi + + # Return to the original directory + cd "$DIR" || exit 1 + fi +done + +# Print header +printf "%-40s %15s %-10s %-10s\n" "Repository" "Last Commit" "Changes" "Status" +printf "%-40s %15s %-10s %-10s\n" "----------" "(hours)" "-------" "------" + +# Print dirty repositories first (sorted by changes, descending) +if grep -q "^D|" "$TEMP_FILE" 2>/dev/null; then + printf "\n=== DIRTY REPOSITORIES ===\n\n" + grep "^D|" "$TEMP_FILE" | sort -t'|' -k3,3nr | while IFS='|' read -r status hours changes repo hours_fmt separator file_list; do + printf "%-40s %15s ${RED}%-10s${NC} ${RED}%-10s${NC}\n" "$repo" "$hours_fmt" "$changes" "Dirty" + # Print the changed files if they exist + if [ -n "$file_list" ]; then + echo -e "$file_list" + fi + done +fi + +# Print clean repositories (sorted by hours, ascending) +if grep -q "^C|" "$TEMP_FILE" 2>/dev/null; then + printf "\n=== CLEAN REPOSITORIES ===\n\n" + grep "^C|" "$TEMP_FILE" | sort -t'|' -k2,2n | while IFS='|' read -r status hours changes repo hours_fmt; do + printf "%-40s %15s %-10s %-10s\n" "$repo" "$hours_fmt" "$changes" "Clean" + done +fi \ No newline at end of file