Mac-Entwicklungsumgebung wöchentlich warten — brew · Toolchains · SDKs mit einem Befehl aktualisieren
Ein einzelnes wöchentliches Shell-Skript, das Homebrew, Mac App Store, npm globals, rustup, Cargo-Binärdateien, pipx, Flutter, CocoaPods und oh-my-zsh aktualisiert.
Man steckt Zeit in die Einrichtung eines neuen Geräts — und vergisst dann, es aktuell zu halten. Zwei Monate später schleppt ein einzelnes brew install 30 transitive Abhängigkeiten mit, native Builds schlagen wegen SDK-Nichtübereinstimmungen fehl, und die Sicherheitszertifikate (ca-certificates) driften still dem Ablauf entgegen.
Ich denke, was eine wöchentliche Update-Routine so wertvoll macht, ist nicht das Updaten selbst, sondern das Wissen, wann ein Update gebrochen ist — weil ein integriertes Skript, das jeden Schritt meldet, sofortiges Feedback gibt, statt dass man Wochen später mysteriöse Build-Fehler debuggt. Früher habe ich Updates ad hoc durchgeführt; heute ist das wöchentliche Skript mein Standard, da ich verstanden habe, dass koordiniertes Updaten weniger Reibung erzeugt als zufällige Einzelupdates.
Dieser Artikel liefert das 9-Schritte-Integrationsscript, das genau das verhindert. Einmal pro Woche ausführen — fertig.
TL;DR
- Führt
brew+mas+npm -g+rustup+cargo install-update+pipx+flutter+pod+omzder Reihe nach aus - Jeder Schritt überspringt automatisch, wenn das Tool nicht installiert ist, und ein Fehler in einem stoppt den Rest nicht
- Endet mit einem nur zur Information macOS-System-Update-Check (kein Auto-Install — Neustarts sind zu riskant)
- ~100 Zeilen einfaches bash
Warum der Aufwand
1. Zertifikat-Ablauf
ca-certificates liefert jedes Quartal ein neues Bundle. Zwei Quartale überspringen und einige HTTPS-Aufrufe schlagen fehl. Du denkst vielleicht, es betrifft dich nicht, aber npm-Registry, Homebrew selbst und die GitHub-API sind alle betroffen.
2. Mobile Build SDK-Drift
Besonders riskant auf Flutter/iOS-Geräten. Flutter stable wird 3–4 Mal pro Monat ausgeliefert; das CocoaPods-Spec-Repo wirft bei pod install „spec not found", wenn es eine Woche nicht synchronisiert wurde. Ein wöchentliches pod repo update allein beseitigt 80 % dieses Schmerzes.
3. Sprach-Toolchain-Anhäufung
Globals, die über rustup, pipx oder cargo installiert sind, benötigen jeweils ihre eigenen Updates. Vergiss es, und eines Tages wirst du entdecken, dass cargo install das Neueste nicht holen kann wegen rust-version-Nichtübereinstimmung.
Voraussetzungen
- macOS 12+ + Homebrew (Mac-Ersteinrichtung)
- Für die vollen 9 Schritte:
mas,pipx,cargo-update,flutter,cocoapods,oh-my-zshvorinstalliert - Einige Tools fehlen ist in Ordnung — diese Schritte werden SKIP elegant
Einmalige Vorbereitung
brew install mas pipx cocoapods
brew install --cask flutter
cargo install cargo-update
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
pipx ensurepathcargo install cargo-update kompiliert den ersten Lauf — das dauert 2–3 Minuten. Flutter ist beim ersten Download ~1 GB groß.
9 Update-Schritte
| # | Schritt | Befehl | Hinweise |
|---|---|---|---|
| 1 | Homebrew | brew update && brew upgrade && brew cleanup | Formeln + Casks |
| 2 | Mac App Store | mas upgrade | App-Store-Apps (Xcode usw.) |
| 3 | npm globals | npm update -g | Globale npm-Pakete |
| 4 | Rust-Toolchain | rustup update | Stable-Kanal |
| 5 | Cargo-Binärdateien | cargo install-update -a | Erfordert cargo-update-Erweiterung |
| 6 | pipx | pipx upgrade-all | Globale Python-Tools |
| 7 | Flutter SDK | flutter upgrade | Aktuellste des aktuellen Kanals |
| 8 | CocoaPods-Repo | pod repo update | iOS-Build-Spec-Synchronisierung |
| 9 | oh-my-zsh | ~/.oh-my-zsh/tools/upgrade.sh | zsh-Framework |
Das integrierte Skript
Als z. B. ~/bin/update-system.sh speichern. chmod +x und verwenden.
#!/usr/bin/env bash
#
# Bulk-System-Tool-Update — macOS
# Verwendung: ./update-system.sh
#
# Umfang:
# 1. Homebrew (Formeln + Casks)
# 2. Mac App Store (mas, wenn installiert)
# 3. npm globals
# 4. Rust-Toolchain (rustup)
# 5. Cargo-Binärdateien (cargo install-update -a, benötigt cargo-update)
# 6. pipx (Globale Python-Tools)
# 7. Flutter SDK (flutter upgrade)
# 8. CocoaPods-Repo (pod repo update — iOS-Build-Dep)
# 9. oh-my-zsh (omz update)
#
# Endet mit `softwareupdate -l` Hinweis (kein Auto-Install — Neustart-Risiko)
#
set -uo pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
CYAN='\033[0;36m'
GRAY='\033[0;90m'
NC='\033[0m'
TOTAL=9
STEP=0
step() {
STEP=$((STEP + 1))
printf "\n${CYAN}[%d/%d] %s${NC}\n" "$STEP" "$TOTAL" "$1"
}
ok() { printf " ${GREEN}OK${NC} %s\n" "$1"; }
skip() { printf " ${GRAY}SKIP${NC} %s\n" "$1"; }
warn() { printf " ${YELLOW}WARN${NC} %s\n" "$1"; }
fail() { printf " ${RED}FAIL${NC} %s\n" "$1"; }
printf "${CYAN}━━━ System-Update (macOS) ━━━${NC}\n"
# fnm initialisieren, damit npm-Schritt Node finden kann
if command -v fnm >/dev/null 2>&1; then
eval "$(fnm env --use-on-cd --shell bash 2>/dev/null)" 2>/dev/null || true
fi
# 1. Homebrew
step "Homebrew (Formeln + Casks)"
if command -v brew >/dev/null 2>&1; then
if brew update && brew upgrade && brew cleanup; then
ok "brew update / upgrade / cleanup"
else
fail "brew-Schritt teilweise fehlgeschlagen — Log oben prüfen"
fi
else
skip "brew nicht installiert"
fi
# 2. Mac App Store
step "Mac App Store (mas)"
if command -v mas >/dev/null 2>&1; then
mas upgrade && ok "mas upgrade" || fail "mas upgrade"
else
skip "mas nicht installiert (brew install mas)"
fi
# 3. npm globals
step "npm globals"
if command -v npm >/dev/null 2>&1; then
npm update -g && ok "npm update -g" || fail "npm update -g"
else
skip "npm nicht installiert"
fi
# 4. Rust-Toolchain
step "Rust-Toolchain (rustup)"
if command -v rustup >/dev/null 2>&1; then
rustup update && ok "rustup update" || fail "rustup update"
else
skip "rustup nicht installiert"
fi
# 5. Cargo-Binärdateien
step "Cargo-Binärdateien (cargo install-update -a)"
if command -v cargo >/dev/null 2>&1; then
if cargo install-update --version >/dev/null 2>&1; then
cargo install-update -a && ok "cargo install-update -a" || fail "cargo install-update -a"
else
warn "cargo-update fehlt (installieren: cargo install cargo-update)"
fi
else
skip "cargo nicht installiert"
fi
# 6. pipx
step "pipx (Globale Python-Tools)"
if command -v pipx >/dev/null 2>&1; then
pipx upgrade-all && ok "pipx upgrade-all" || fail "pipx upgrade-all"
else
skip "pipx nicht installiert (brew install pipx)"
fi
# 7. Flutter SDK
step "Flutter SDK (flutter upgrade)"
if command -v flutter >/dev/null 2>&1; then
flutter upgrade && ok "flutter upgrade" || fail "flutter upgrade"
else
skip "flutter nicht installiert"
fi
# 8. CocoaPods-Repo
step "CocoaPods-Repo (pod repo update)"
if command -v pod >/dev/null 2>&1; then
pod repo update && ok "pod repo update" || fail "pod repo update"
else
skip "pod nicht installiert (brew install cocoapods)"
fi
# 9. oh-my-zsh
step "oh-my-zsh (omz update)"
if [ -d "$HOME/.oh-my-zsh" ]; then
OMZ_UPDATER="$HOME/.oh-my-zsh/tools/upgrade.sh"
if [ -x "$OMZ_UPDATER" ]; then
zsh "$OMZ_UPDATER" && ok "oh-my-zsh aktualisiert" || fail "oh-my-zsh"
else
skip "oh-my-zsh upgrade.sh fehlt"
fi
else
skip "oh-my-zsh nicht installiert"
fi
# macOS-System-Update — nur zur Information
printf "\n${CYAN}━━━ macOS System-Update-Check (nur zur Information) ━━━${NC}\n"
if command -v softwareupdate >/dev/null 2>&1; then
SU_OUT=$(softwareupdate -l 2>&1)
if echo "$SU_OUT" | grep -qi "no new software\|No updates"; then
printf "${GRAY} Aktuell — keine System-Updates${NC}\n"
else
printf "${YELLOW} ⚠ System-Updates verfügbar:${NC}\n"
echo "$SU_OUT" | sed 's/^/ /'
printf "${GRAY} Installieren mit: sudo softwareupdate -ia --restart (startet neu)${NC}\n"
fi
fi
printf "\n${CYAN}━━━ Fertig ━━━${NC}\n"
printf "${GRAY}Checks: brew doctor / brew outdated / npm outdated -g / flutter doctor${NC}\n"Beispielausgabe
Der erste Lauf ist lang (5 Minuten, wenn brew 13 ausstehende Upgrades hat). Folgeläufe dauern 1–2 Minuten.
━━━ System-Update (macOS) ━━━
[1/9] Homebrew (Formeln + Casks)
==> Upgrading 13 outdated packages:
ca-certificates 2026-03-19 -> 2026-05-14
ruby 4.0.3 -> 4.0.4
sqlite 3.53.0 -> 3.53.1
python@3.14 3.14.4_1 -> 3.14.5
...
==> This operation has freed approximately 18.8MB of disk space.
OK brew update / upgrade / cleanup
[2/9] Mac App Store (mas)
OK mas upgrade
[3/9] npm globals
OK npm update -g
[4/9] Rust-Toolchain (rustup)
stable-aarch64-apple-darwin unchanged - rustc 1.95.0
OK rustup update
...
[9/9] oh-my-zsh (omz update)
Hooray! Oh My Zsh has been updated!
OK oh-my-zsh aktualisiert
━━━ macOS System-Update-Check (nur zur Information) ━━━
Aktuell — keine System-Updates
━━━ Fertig ━━━
Automatisierung — Wie weit?
Vollständige Automatisierung wird nicht empfohlen. Große brew-Versions-Sprünge (z. B. vercel-cli 53→54) bringen gelegentlich Breaking Changes mit, die man direkt nach dem Update bemerken sollte.
Ein vernünftiger Mittelweg ist eine Erinnerung, kein Auto-Run:
~/Library/LaunchAgents/local.update-reminder.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key><string>local.update-reminder</string>
<key>ProgramArguments</key>
<array>
<string>osascript</string>
<string>-e</string>
<string>display notification "Wöchentlicher update-system Check" with title "Dev Maintenance"</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Weekday</key><integer>5</integer>
<key>Hour</key><integer>10</integer>
<key>Minute</key><integer>0</integer>
</dict>
</dict>
</plist>Aktivieren:
launchctl load -w ~/Library/LaunchAgents/local.update-reminder.plistJeden Freitag um 10:00 Uhr eine einzelne Desktop-Benachrichtigung. Du entscheidest, wann du ausführst.
Stolperfallen
- Kein Auto-Install für macOS-System-Updates:
softwareupdate -ia --restarterzwingt einen Neustart. IDE, Terminals, Docker-Container — alles weg. Das Skript listet nur verfügbare Updates auf; die Installation erfolgt manuell zu einem selbst gewählten Zeitpunkt. pod repo updateist langsam (5+ Minuten möglich): Das Trunk-Repo ist groß — umso länger, je mehr Wochen übersprungen wurden.- Oh My Zsh hat eine eigene Auto-Update-Option:
.zshrc-Einstellungzstyle ':omz:update' mode auto. Harmlose Überschneidung mit diesem Skript. - Cargo kompiliert:
cargo install-update -akompiliert frische Versionen installierter Binärdateien — der erste Lauf kann mehrere Minuten dauern.
Windows-Nutzer?
Dieselbe Idee in PowerShell, abdeckend MSYS2 + winget + Sprach-Toolchains → Windows-Entwicklungsumgebung wöchentliche Wartung.
Zusammenfassung
- Einzeln aktualisieren → geht in Vergessenheit
- Einzelnes integriertes Skript → einfach ausführen, fertig
- Automatisierung nur als Erinnerung, niemals als Auto-Run
- Einmal pro Woche verhindert brew-Abhängigkeits-Stürme, SDK-Drift und Zertifikat-Ablauf