#!/bin/bash # Git audit: check all projects in ~/dev/ for unpushed changes # Reports anomalies only (unpushed commits, uncommitted changes, missing remotes) # Run hourly via cron DEV_DIR="/home/johan/dev" ANOMALIES="" for dir in "$DEV_DIR"/*/; do [ ! -d "$dir/.git" ] && continue repo=$(basename "$dir") cd "$dir" # Check for remote if ! git remote get-url origin &>/dev/null; then ANOMALIES+="❌ $repo: NO REMOTE — needs git@zurich.inou.com:$repo.git\n" continue fi # Check for uncommitted changes DIRTY=$(git status --porcelain 2>/dev/null) if [ -n "$DIRTY" ]; then COUNT=$(echo "$DIRTY" | wc -l) ANOMALIES+="⚠️ $repo: $COUNT uncommitted file(s)\n" fi # Check for unpushed commits (fetch first to be accurate, with timeout) timeout 10 git fetch origin --quiet 2>/dev/null BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) if [ -n "$BRANCH" ]; then AHEAD=$(git rev-list --count "origin/$BRANCH..HEAD" 2>/dev/null) if [ -n "$AHEAD" ] && [ "$AHEAD" -gt 0 ]; then ANOMALIES+="🔺 $repo: $AHEAD unpushed commit(s) on $BRANCH\n" fi fi done # Also check ~/clawd/ workspace cd /home/johan/clawd if [ -d .git ]; then DIRTY=$(git status --porcelain 2>/dev/null) if [ -n "$DIRTY" ]; then COUNT=$(echo "$DIRTY" | wc -l) ANOMALIES+="⚠️ clawd: $COUNT uncommitted file(s)\n" fi BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) if [ -n "$BRANCH" ] && git remote get-url origin &>/dev/null; then timeout 10 git fetch origin --quiet 2>/dev/null AHEAD=$(git rev-list --count "origin/$BRANCH..HEAD" 2>/dev/null) if [ -n "$AHEAD" ] && [ "$AHEAD" -gt 0 ]; then ANOMALIES+="🔺 clawd: $AHEAD unpushed commit(s) on $BRANCH\n" fi fi fi if [ -n "$ANOMALIES" ]; then echo -e "Git audit found issues:\n$ANOMALIES" exit 1 else exit 0 fi