From dfc21f4cfa70600776c8b50bfdd58e3c53781d14 Mon Sep 17 00:00:00 2001 From: rene Date: Sat, 14 Mar 2026 08:29:52 +0100 Subject: [PATCH] git-sync-all.sh: Repos klonen, pullen und pushen in einem Befehl --- bin/git-sync-all.sh | 190 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100755 bin/git-sync-all.sh diff --git a/bin/git-sync-all.sh b/bin/git-sync-all.sh new file mode 100755 index 0000000..3c32aca --- /dev/null +++ b/bin/git-sync-all.sh @@ -0,0 +1,190 @@ +#!/usr/bin/env bash +set -uo pipefail + +BASE_DIR="${BASE_DIR:-$HOME/git-projekte}" +GITEA_BASE="https://git.motocamp.de/rene" + +# Alle Repos auf dem Gitea-Server. +# Bei neuen Repos hier einen Eintrag ergaenzen. +REPO_NAMES=( + balkonsteuerung + berechnungstabellen + claude-skills + comfy + dotfiles-rene + esp32 + ki-agenten + macbook-setup + Pi_pico_2w + portainer + skripte + test + web + zellenhalter-generator +) + +# --- Farben ---------------------------------------------------------------- +if [ -t 1 ]; then + C_RED=$'\033[31m' + C_GREEN=$'\033[32m' + C_YELLOW=$'\033[33m' + C_CYAN=$'\033[36m' + C_BOLD=$'\033[1m' + C_RESET=$'\033[0m' +else + C_RED=""; C_GREEN=""; C_YELLOW=""; C_CYAN=""; C_BOLD=""; C_RESET="" +fi + +# --- Argumente ------------------------------------------------------------- +DRY_RUN=false +while [[ $# -gt 0 ]]; do + case "$1" in + -p|--path) BASE_DIR="$2"; shift 2 ;; + -n|--dry-run) DRY_RUN=true; shift ;; + -h|--help) + cat <&2; exit 2 ;; + esac +done + +mkdir -p "$BASE_DIR" + +echo "${C_BOLD}Git-Sync: $BASE_DIR${C_RESET}" +echo + +# --- Zaehler --------------------------------------------------------------- +total=0 +cloned=0 +pulled=0 +pushed=0 +dirty=0 +uptodate=0 +failed=0 + +# --- Repos durchgehen ------------------------------------------------------ +for NAME in "${REPO_NAMES[@]}"; do + URL="${GITEA_BASE}/${NAME}.git" + TARGET="$BASE_DIR/$NAME" + ((total++)) + + # 1) Repo fehlt -> klonen + if [ ! -d "$TARGET/.git" ]; then + if [ -d "$TARGET" ]; then + printf "${C_YELLOW}SKIP${C_RESET} %-25s Verzeichnis existiert, kein Git-Repo\n" "$NAME" + ((failed++)) + continue + fi + if $DRY_RUN; then + printf "${C_CYAN}CLONE${C_RESET} %-25s (dry-run)\n" "$NAME" + else + if git clone --quiet "$URL" "$TARGET" 2>/dev/null; then + printf "${C_CYAN}CLONE${C_RESET} %-25s geklont\n" "$NAME" + ((cloned++)) + else + printf "${C_RED}FAIL${C_RESET} %-25s Klonen fehlgeschlagen\n" "$NAME" + ((failed++)) + fi + fi + continue + fi + + # Ab hier: Repo existiert + cd "$TARGET" || continue + + # Remote fetch + git fetch --quiet 2>/dev/null || true + + # 2) Uncommittete Aenderungen? + has_changes=false + if [[ -n "$(git status --porcelain 2>/dev/null)" ]]; then + has_changes=true + fi + + # 3) Ahead/Behind + ahead=0 + behind=0 + upstream_info="$(git rev-list --left-right --count "@{u}...HEAD" 2>/dev/null || true)" + if [[ -n "$upstream_info" ]]; then + read -r behind ahead <<<"$upstream_info" + fi + + # 4) Aktionen + did_something=false + + # Pull wenn behind + if ((behind > 0)); then + if $has_changes; then + printf "${C_YELLOW}DIRTY${C_RESET} %-25s %d neue Remote-Commits + lokale Aenderungen\n" "$NAME" "$behind" + ((dirty++)) + if ((ahead > 0)); then + printf " %-25s + %d lokale Commits nicht gepusht\n" "" "$ahead" + fi + continue + fi + if $DRY_RUN; then + printf "${C_GREEN}PULL${C_RESET} %-25s %d Commits (dry-run)\n" "$NAME" "$behind" + else + if git pull --ff-only --quiet 2>/dev/null; then + printf "${C_GREEN}PULL${C_RESET} %-25s %d Commits geholt\n" "$NAME" "$behind" + ((pulled++)) + else + printf "${C_RED}FAIL${C_RESET} %-25s Pull fehlgeschlagen (evtl. diverged)\n" "$NAME" + ((failed++)) + continue + fi + fi + did_something=true + fi + + # Push wenn ahead + if ((ahead > 0)); then + if $DRY_RUN; then + printf "${C_GREEN}PUSH${C_RESET} %-25s %d Commits (dry-run)\n" "$NAME" "$ahead" + else + if git push --quiet 2>/dev/null; then + printf "${C_GREEN}PUSH${C_RESET} %-25s %d Commits gepusht\n" "$NAME" "$ahead" + ((pushed++)) + else + printf "${C_RED}FAIL${C_RESET} %-25s Push fehlgeschlagen\n" "$NAME" + ((failed++)) + fi + fi + did_something=true + fi + + if ! $did_something; then + if $has_changes; then + printf "${C_YELLOW}DIRTY${C_RESET} %-25s uncommittete Aenderungen\n" "$NAME" + ((dirty++)) + else + printf "${C_GREEN}OK${C_RESET} %-25s aktuell\n" "$NAME" + ((uptodate++)) + fi + fi +done + +# --- Zusammenfassung ------------------------------------------------------- +echo +echo "${C_BOLD}Gesamt:${C_RESET} $total Repositories" +((cloned > 0)) && echo "${C_CYAN}Geklont:${C_RESET} $cloned" +((pulled > 0)) && echo "${C_GREEN}Gepullt:${C_RESET} $pulled" +((pushed > 0)) && echo "${C_GREEN}Gepusht:${C_RESET} $pushed" +((dirty > 0)) && echo "${C_YELLOW}Dirty:${C_RESET} $dirty" +((failed > 0)) && echo "${C_RED}Fehlgeschlagen:${C_RESET} $failed" +((uptodate > 0)) && echo "${C_GREEN}Aktuell:${C_RESET} $uptodate" +echo