#!/usr/bin/env bash # claude-sync — git pull before Claude, commit+push after. # Safe on conflicts: never merges/forces; just reports and lets you resolve. # The MiniTerm app cd's into the project dir first, so git runs on the CWD. set -uo pipefail # Aus dem GUI gestartet (ghostty-App) erbt der Prozess nur den launchd-PATH # (/usr/bin:/bin:…) — ~/.local/bin fehlt, also würde `claude` unten nicht # gefunden und das Skript sofort enden. Eigenes Verzeichnis (dort liegt der # claude-Symlink) voranstellen. self_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" export PATH="$self_dir:$PATH" ok() { printf '\033[1;32m✓ %s\033[0m\n' "$*"; } # green note() { printf '\033[1;36m· %s\033[0m\n' "$*"; } # cyan warn() { printf '\033[1;33m⚠ %s\033[0m\n' "$*"; } # yellow # --- Is this a git repo with a remote? ------------------------------------- if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then warn "Kein Git-Repo hier — starte Claude ohne Sync." exec claude "$@" fi have_remote=0 git remote get-url origin >/dev/null 2>&1 && have_remote=1 branch=$(git rev-parse --abbrev-ref HEAD) # --- PULL before start ------------------------------------------------------ if [[ "$have_remote" -eq 1 ]]; then git fetch --quiet origin "$branch" 2>/dev/null || true if git rev-parse --verify --quiet "origin/$branch" >/dev/null; then behind=$(git rev-list --count "HEAD..origin/$branch" 2>/dev/null || echo 0) if [[ "$behind" -eq 0 ]]; then ok "git pull: bereits aktuell ($branch)." elif git merge --ff-only "origin/$branch" >/dev/null 2>&1; then ok "git pull: $behind Commit(s) geholt ($branch)." else warn "git pull übersprungen — kein sauberer Fast-Forward (lokale Änderungen oder divergierte History). Bitte manuell lösen." fi else note "Kein Remote-Branch '$branch' — Pull übersprungen." fi else note "Kein origin-Remote — Sync übersprungen." fi # --- run Claude ------------------------------------------------------------- claude "$@" claude_rc=$? # --- PUSH after end --------------------------------------------------------- if [[ "$have_remote" -eq 1 ]]; then # Commit any working-tree changes (CLAUDE.md, memories, ...) so they can be pushed. if [[ -n "$(git status --porcelain)" ]]; then git add -A git commit --quiet -m "claude sync: $(date '+%Y-%m-%d %H:%M')" && \ note "Änderungen committed." fi if git rev-parse --abbrev-ref --symbolic-full-name '@{u}' >/dev/null 2>&1; then ahead=$(git rev-list --count '@{u}..HEAD' 2>/dev/null || echo 0) if [[ "$ahead" -eq 0 ]]; then note "git push: nichts zu pushen." elif git push --quiet 2>/dev/null; then ok "git push: $ahead Commit(s) gepusht." else warn "git push abgelehnt — Remote hat neue Commits. Bitte manuell mergen/pushen." fi else if git push --quiet -u origin "$branch" 2>/dev/null; then ok "git push: Upstream gesetzt und gepusht." else warn "Kein Upstream gesetzt, automatischer Push fehlgeschlagen — bitte einmal manuell pushen." fi fi fi exit "$claude_rc"