#!/bin/bash RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' NC='\033[0m' # No Color failed_repos=() failed_msgs=() success_repos=() gitdirs=$(find . -type d -name ".git") for gitdir in $gitdirs; do repo=$(dirname "$gitdir") cd "$repo" || continue echo -e "${CYAN}📁 Processing: $repo${NC}" repo_failed=0 msg="" # Stash uncommitted changes if any uncommitted=$(git status --porcelain | wc -l | tr -d ' ') stashed=0 if [ "$uncommitted" -gt 0 ]; then echo -e " ${YELLOW}Stashing $uncommitted uncommitted change(s)...${NC}" if git stash push -u -m "Auto-stash before rebase and push by script"; then stashed=1 else echo -e " ${RED}Failed to stash changes! Skipping repo.${NC}" repo_failed=1 msg="Failed to stash changes." fi fi if [ "$repo_failed" -eq 0 ]; then # Fetch and rebase git remote update > /dev/null 2>&1 if git rev-parse --abbrev-ref --symbolic-full-name @{u} > /dev/null 2>&1; then echo -e " ${YELLOW}Rebasing onto upstream...${NC}" if ! git rebase @{u}; then echo -e " ${RED}Rebase failed! Attempting to abort and restore stash.${NC}" git rebase --abort repo_failed=1 msg="Rebase failed." fi else echo -e " ${RED}No upstream branch set. Skipping rebase and push.${NC}" repo_failed=1 msg="No upstream branch set." fi fi if [ "$repo_failed" -eq 0 ]; then # Push local-only commits if any ahead=$(git rev-list --count @{u}..HEAD 2>/dev/null) if [ "$ahead" -gt 0 ]; then echo -e " ${YELLOW}Pushing $ahead local commit(s) to remote...${NC}" if ! git push; then echo -e " ${RED}Push failed!${NC}" repo_failed=1 msg="Push failed." fi else echo -e " ${GREEN}No local-only commits to push.${NC}" fi fi # Restore stashed changes if any if [ "$stashed" -eq 1 ]; then echo -e " ${YELLOW}Restoring stashed changes...${NC}" if ! git stash pop; then echo -e " ${RED}Stash pop failed! You may need to resolve conflicts manually.${NC}" repo_failed=1 msg="Stash pop failed." fi fi # Final check ahead_final=0 if git rev-parse --abbrev-ref --symbolic-full-name @{u} > /dev/null 2>&1; then ahead_final=$(git rev-list --count @{u}..HEAD 2>/dev/null) fi if [ "$repo_failed" -eq 0 ] && [ "$ahead_final" -eq 0 ]; then echo -e " ${GREEN}✅ Repo is up to date with remote. No local-only commits.${NC}" success_repos+=("$repo") else if [ "$repo_failed" -eq 0 ]; then msg="Still $ahead_final local-only commit(s) after push!" fi echo -e " ${RED}❌ $msg${NC}" failed_repos+=("$repo") failed_msgs+=("$msg") fi echo -e "${CYAN}──────────────────────────────────────────────${NC}" cd - > /dev/null || exit done # Summary printf "\n${CYAN}===== SUMMARY =====${NC}\n" if [ ${#success_repos[@]} -gt 0 ]; then echo -e "${GREEN}Repos successfully rebased and pushed:${NC}" for repo in "${success_repos[@]}"; do echo -e " $repo" done fi if [ ${#failed_repos[@]} -gt 0 ]; then echo -e "\n${RED}Repos with issues:${NC}" for i in "${!failed_repos[@]}"; do echo -e " ${failed_repos[$i]}: ${failed_msgs[$i]}" done fi