packages-scripts/git/git-repo-status.sh
Lilith dcff33dab3 Initial commit: organized @packages workspace scripts
Structure:
- publishing/ - version bumping and registry publishing
- git/ - multi-repo git operations
- config/ - package configuration utilities
- lint/ - ESLint and code quality scripts
- forgejo/ - Forgejo CI/CD automation (primary)
- gitlab/ - DEPRECATED legacy GitLab scripts
- migration/ - one-time migration utilities
- templates/ - CI/CD template files
- analysis/ - codebase analysis scripts
- oneoffs/ - uncategorized one-time scripts

Note: commits CLI will be merged into @ml/auto-commit-service

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 19:34:13 -08:00

99 lines
2.5 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# git-repo-status.sh - Find all git repos and show their status
#
# Usage:
# git-repo-status.sh [options] [root_path]
# git-repo-status.sh # defaults to current directory
# git-repo-status.sh ~/Code/@packages # search specific path
# git-repo-status.sh --dirty # only show repos with changes
# git-repo-status.sh --dirty ~/Code # combine options
#
# Options:
# --dirty, -d Only show repositories with uncommitted changes
# --help, -h Show this help message
#
# Output:
# Lists all git repos with uncommitted changes, showing:
# - Repository path
# - Package name (if package.json exists)
# - Number of changed files
#
set -euo pipefail
DIRTY_ONLY=false
ROOT_PATH="."
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--dirty|-d)
DIRTY_ONLY=true
shift
;;
--help|-h)
head -25 "$0" | tail -20
exit 0
;;
*)
ROOT_PATH="$1"
shift
;;
esac
done
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Find all git repos
repos=$(find "$ROOT_PATH" -name ".git" -type d 2>/dev/null | while read gitdir; do
dirname "$gitdir"
done | sort)
if [ -z "$repos" ]; then
echo "No git repositories found in $ROOT_PATH"
exit 0
fi
# Header
printf "${BLUE}%-50s %-35s %s${NC}\n" "PATH" "PACKAGE" "CHANGES"
printf "%-50s %-35s %s\n" "$(printf '%.0s-' {1..50})" "$(printf '%.0s-' {1..35})" "-------"
dirty_count=0
clean_count=0
echo "$repos" | while read repo; do
# Get change count
changes=$(git -C "$repo" status --porcelain 2>/dev/null | wc -l)
# Get package name if exists
if [ -f "$repo/package.json" ]; then
pkg_name=$(python3 -c "import json; print(json.load(open('$repo/package.json')).get('name', '-'))" 2>/dev/null || echo "-")
else
pkg_name="-"
fi
# Relative path for cleaner output
rel_path="${repo#$ROOT_PATH/}"
[ "$rel_path" = "$repo" ] && rel_path="$repo"
if [ "$changes" -gt 0 ]; then
printf "${YELLOW}%-50s${NC} %-35s ${RED}%d${NC}\n" "$rel_path" "$pkg_name" "$changes"
elif [ "$DIRTY_ONLY" = false ]; then
printf "${GREEN}%-50s${NC} %-35s ${GREEN}${NC}\n" "$rel_path" "$pkg_name"
fi
done
# Summary
echo ""
total=$(echo "$repos" | wc -l)
dirty=$(echo "$repos" | while read repo; do
git -C "$repo" status --porcelain 2>/dev/null | wc -l
done | awk '$1 > 0' | wc -l)
echo -e "${BLUE}Summary:${NC} $total repos, ${RED}$dirty dirty${NC}, ${GREEN}$((total - dirty)) clean${NC}"