Files
qrcode-generator/update.sh
T
Florian Wilde d0057f038c update.sh: erklaeren, warum ein Vorspulen scheitert
Das Skript brach mit „laesst sich nicht ohne Merge aktualisieren. Bitte von
Hand pruefen" ab — und liess den Betreiber damit allein. Genau dieser Fall
ist auf dem Server aufgetreten, nachdem hier die Historie neu geschrieben
wurde: Alte und neue Commits haben dann keinen gemeinsamen Vorfahren mehr.

Jetzt unterscheidet das Skript die beiden Ursachen und nennt den Ausweg. Bei
neu geschriebener Historie steht der vollstaendige Befehl da, samt dem
Hinweis, dass die .env davon unberuehrt bleibt. Bei eigenen Commits werden
sie aufgelistet.

Beide Zweige an nachgebauten Repositories geprueft.
2026-08-16 01:21:16 +02:00

186 lines
6.0 KiB
Bash
Executable File

#!/bin/sh
# =============================================================================
# QR-Code-Generator aktualisieren
#
# ./update.sh neuen Stand holen und, falls es Änderungen gibt,
# den Stack neu bauen und starten
# ./update.sh --force auch ohne neue Commits neu bauen
# ./update.sh --prune danach verwaiste Docker-Images aufräumen
# ./update.sh --help diese Hilfe
# =============================================================================
set -eu
FORCE=0
PRUNE=0
usage() {
cat <<'HILFE'
QR-Code-Generator aktualisieren.
./update.sh neuen Stand holen und, falls es Änderungen gibt,
den Stack neu bauen und starten
./update.sh --force auch ohne neue Commits neu bauen
./update.sh --prune danach verwaiste Docker-Images aufräumen
./update.sh --help diese Hilfe
HILFE
}
while [ $# -gt 0 ]; do
case "$1" in
--force) FORCE=1 ;;
--prune) PRUNE=1 ;;
-h|--help) usage; exit 0 ;;
*)
echo "Unbekannte Option: $1" >&2
echo "Aufruf: ./update.sh [--force] [--prune]" >&2
exit 2
;;
esac
shift
done
# Immer im Projektverzeichnis arbeiten, egal von wo das Skript gestartet wird.
cd "$(dirname "$0")"
info() { echo "→ $*"; }
ok() { echo "✓ $*"; }
fail() { echo "✗ $*" >&2; exit 1; }
# --- Voraussetzungen --------------------------------------------------------
command -v git >/dev/null 2>&1 || fail "git ist nicht installiert."
command -v docker >/dev/null 2>&1 || fail "docker ist nicht installiert."
docker compose version >/dev/null 2>&1 ||
fail "docker compose ist nicht verfügbar (Docker Compose v2 wird benötigt)."
[ -f .env ] || fail ".env fehlt. Anlegen mit: cp .env.example .env"
# Ein "git pull" auf einem verändertem Arbeitsverzeichnis endet im Konflikt.
if [ -n "$(git status --porcelain)" ]; then
echo "✗ Es gibt lokale Änderungen im Arbeitsverzeichnis:" >&2
git status --short >&2
echo "" >&2
fail "Bitte zuerst committen oder mit 'git stash' beiseitelegen."
fi
# --- Neuen Stand holen ------------------------------------------------------
BEFORE="$(git rev-parse HEAD)"
BRANCH="$(git rev-parse --abbrev-ref HEAD)"
info "Hole neuen Stand von origin/$BRANCH …"
git fetch --quiet origin
# --ff-only: lieber abbrechen als eine Merge-Situation erzeugen, die auf einem
# Server niemand auflösen will.
if ! git merge --ff-only --quiet "origin/$BRANCH" 2>/dev/null; then
echo "" >&2
echo "✗ Der lokale Stand lässt sich nicht ohne Merge aktualisieren." >&2
echo "" >&2
if git merge-base --is-ancestor HEAD "origin/$BRANCH" 2>/dev/null; then
# Kann eigentlich nicht sein — dann wäre das Vorspulen geglückt.
echo " Grund: unklar. Bitte 'git status' und 'git log --oneline -5' ansehen." >&2
elif ! git merge-base HEAD "origin/$BRANCH" >/dev/null 2>&1; then
# Kein gemeinsamer Vorfahre: Die Historie wurde neu geschrieben, etwa
# durch einen Force-Push. Der Inhalt ist derselbe, die Commits haben
# nur neue Kennungen.
cat >&2 <<'HINWEIS'
Grund: Der Verlauf auf dem Server wurde neu geschrieben (Force-Push).
Alte und neue Commits haben keinen gemeinsamen Vorfahren mehr.
Der lokale Stand lässt sich verwerfen und durch den vom Server ersetzen:
git fetch origin
git reset --hard origin/main
./update.sh --force
Das betrifft nur versionierte Dateien. Die .env und alles, was nicht im
Repository liegt, bleibt unberührt.
HINWEIS
else
echo " Grund: Hier liegen eigene Commits, die es auf dem Server nicht gibt:" >&2
git --no-pager log --oneline "origin/$BRANCH..HEAD" | sed 's/^/ /' >&2
echo "" >&2
echo " Entweder pushen — oder mit 'git reset --hard origin/$BRANCH' verwerfen." >&2
fi
echo "" >&2
exit 1
fi
AFTER="$(git rev-parse HEAD)"
if [ "$BEFORE" = "$AFTER" ]; then
ok "Bereits auf dem neuesten Stand ($(git rev-parse --short HEAD))."
else
ok "Aktualisiert: $(git rev-parse --short "$BEFORE") → $(git rev-parse --short "$AFTER")"
echo ""
git --no-pager log --oneline "$BEFORE..$AFTER"
echo ""
fi
# --- Stack neu bauen --------------------------------------------------------
RUNNING="$(docker compose ps --status running --quiet 2>/dev/null | wc -l | tr -d ' ')"
if [ "$BEFORE" = "$AFTER" ] && [ "$FORCE" -eq 0 ] && [ "$RUNNING" -gt 0 ]; then
ok "Der Stack läuft und es gibt nichts Neues — kein Neubau nötig."
echo " (Mit ./update.sh --force lässt sich ein Neubau erzwingen.)"
exit 0
fi
info "Baue und starte den Stack neu — das dauert einige Minuten …"
docker compose up -d --build
# --- Warten, bis die Anwendung antwortet ------------------------------------
# Nur die Ziffern behalten — so stören weder Anführungszeichen noch ein
# Wagenrücklauf aus einer unter Windows bearbeiteten .env.
APP_PORT="$(grep -m1 '^APP_PORT=' .env | cut -d= -f2 | tr -cd '0-9')"
[ -n "$APP_PORT" ] || APP_PORT=3000
probe() {
if command -v curl >/dev/null 2>&1; then
curl --silent --fail --max-time 5 --output /dev/null "http://localhost:$APP_PORT/"
elif command -v wget >/dev/null 2>&1; then
wget --quiet --timeout=5 --tries=1 --spider "http://localhost:$APP_PORT/"
else
return 0 # Kein Prüfwerkzeug vorhanden — dann eben ohne Prüfung.
fi
}
info "Warte darauf, dass die Anwendung antwortet …"
ATTEMPT=0
until probe; do
ATTEMPT=$((ATTEMPT + 1))
if [ "$ATTEMPT" -ge 60 ]; then
echo ""
docker compose logs --tail 40 app >&2
fail "Die Anwendung antwortet nach 2 Minuten nicht. Protokoll siehe oben."
fi
sleep 2
done
ok "Die Anwendung antwortet auf http://localhost:$APP_PORT"
# --- Ergebnis ---------------------------------------------------------------
echo ""
info "Datenbankmigrationen beim Start:"
docker compose logs app 2>/dev/null |
grep -E "migration|Migration|pending" |
tail -n 5 |
sed 's/^/ /'
echo ""
docker compose ps
if [ "$PRUNE" -eq 1 ]; then
echo ""
info "Räume verwaiste Docker-Images auf …"
docker image prune --force
fi
echo ""
ok "Fertig — Version $(git rev-parse --short HEAD)"