Implement sync script and setup documentation

This commit is contained in:
yves-sbb committed 2026-09-28 18:24:54 +02:00
1 parent eef338d116
commit a7e87691a7
5 files changed
+1400

No files matched your search

+61
View File
@@ -0,0 +1,61 @@
[2026-09-28 18:17:00] ═══════════════════════════════════════════════════════════
[2026-09-28 18:17:00] Modus: status
[2026-09-28 18:17:00] ═══════════════════════════════════════════════════════════
[2026-09-28 18:17:00] Status: Vergleiche Repo mit Home-Dir...
[2026-09-28 18:17:03] ═══════════════════════════════════════════════════════════
[2026-09-28 18:17:03] Modus: status
[2026-09-28 18:17:03] ═══════════════════════════════════════════════════════════
[2026-09-28 18:17:03] Status: Vergleiche Repo mit Home-Dir...
[2026-09-28 18:17:50] ═══════════════════════════════════════════════════════════
[2026-09-28 18:17:50] Modus: status
[2026-09-28 18:17:50] ═══════════════════════════════════════════════════════════
[2026-09-28 18:17:50] Status: Vergleiche Repo mit Home-Dir...
[2026-09-28 18:17:53] ═══════════════════════════════════════════════════════════
[2026-09-28 18:17:53] Modus: status
[2026-09-28 18:17:53] ═══════════════════════════════════════════════════════════
[2026-09-28 18:17:53] Status: Vergleiche Repo mit Home-Dir...
[DEBUG] ✓ identisch: .bash_aliases
[DEBUG] ✓ identisch: .gitconfig
[DEBUG] ✓ identisch: .gitconfig-architeq
[DEBUG] ✓ identisch: .gitconfig-bc
[DEBUG] ✓ identisch: .gitconfig-nettworks
[DEBUG] ✓ identisch: .gitconfig-private
[DEBUG] ✓ identisch: .gitconfig-ti8m
[DEBUG] ✓ identisch: .gitignore_global
[DEBUG] ✓ identisch: .npmrc
[DEBUG] ✓ identisch: .p10k.zsh
[DEBUG] ✓ identisch: .profile
[DEBUG] ✓ identisch: .testcontainers.properties
[DEBUG] ✓ identisch: .zshrc
[DEBUG] ✓ identisch: getsizes.sh
[OK] Status-Zusammenfassung:
[2026-09-28 18:17:53] ═══════════════════════════════════════════════════════════
[OK] Abgeschlossen
[2026-09-28 18:18:40] ═══════════════════════════════════════════════════════════
[2026-09-28 18:18:40] Modus: list
[2026-09-28 18:18:40] ═══════════════════════════════════════════════════════════
[2026-09-28 18:18:40] Liste alle verwalteten Dateien:
[2026-09-28 18:18:40] ═══════════════════════════════════════════════════════════
[OK] Abgeschlossen
[2026-09-28 18:18:43] ═══════════════════════════════════════════════════════════
[2026-09-28 18:18:43] Modus: push
[2026-09-28 18:18:43] DRY-RUN: Keine Änderungen werden vorgenommen
[2026-09-28 18:18:43] ═══════════════════════════════════════════════════════════
[2026-09-28 18:18:43] Push: Synchronisiere Repo-Dateien ins Home-Dir...
[DEBUG] ⊙ unverändert: .bash_aliases
[DEBUG] ⊙ unverändert: .gitconfig
[DEBUG] ⊙ unverändert: .gitconfig-architeq
[DEBUG] ⊙ unverändert: .gitconfig-bc
[DEBUG] ⊙ unverändert: .gitconfig-nettworks
[DEBUG] ⊙ unverändert: .gitconfig-private
[DEBUG] ⊙ unverändert: .gitconfig-ti8m
[DEBUG] ⊙ unverändert: .gitignore_global
[DEBUG] ⊙ unverändert: .npmrc
[DEBUG] ⊙ unverändert: .p10k.zsh
[DEBUG] ⊙ unverändert: .profile
[DEBUG] ⊙ unverändert: .testcontainers.properties
[DEBUG] ⊙ unverändert: .zshrc
[DEBUG] ⊙ unverändert: getsizes.sh
[OK] Push abgeschlossen: 0 kopiert, 0 Backups, 0 ausgelassen
[2026-09-28 18:18:43] ═══════════════════════════════════════════════════════════
[OK] DRY-RUN abgeschlossen (keine Änderungen)
Executable
+150
View File
@@ -0,0 +1,150 @@
#!/bin/bash
# Quick-Start Guide für sync-home-content.sh
cat << 'EOF'
╔════════════════════════════════════════════════════════════════════════════╗
║ Quick-Start: home-content Synchronisierung ║
╚════════════════════════════════════════════════════════════════════════════╝
📋 KURZVERSION (3 Schritte):
1. Status prüfen:
./sync-home-content.sh status
2. Trockentest:
./sync-home-content.sh sync --dry-run
3. Synchronisieren:
./sync-home-content.sh sync
═══════════════════════════════════════════════════════════════════════════════
🎯 Welcher Modus passt?
┌─ Lokal neue .gitconfig erstellt / bearbeitet
│ → ./sync-home-content.sh pull
│
├─ Git-Pull durchgeführt, Repo hat Updates
│ → ./sync-home-content.sh push
│
├─ "Weiß nicht, was geändert wurde" (safer)
│ → ./sync-home-content.sh sync
│
├─ Nur schauen, nicht ändern
│ → ./sync-home-content.sh status
│
└─ Alte Backups löschen (>30 Tage)
→ ./sync-home-content.sh cleanup
═══════════════════════════════════════════════════════════════════════════════
🛡️ IMMER SO:
TROCKENTEST vor echter Änderung:
./sync-home-content.sh [modus] --dry-run
Dann mit -v (verbose) um Details zu sehen:
./sync-home-content.sh [modus] --dry-run -v
═══════════════════════════════════════════════════════════════════════════════
💾 BACKUPS:
Alle Backups sind in: .sync-backups/
Restore eines Backups:
cp .sync-backups/.gitconfig.20260928_150000.backup home-content/.gitconfig
Alte Backups löschen:
./sync-home-content.sh cleanup
═══════════════════════════════════════════════════════════════════════════════
📝 CHECKLISTE für Anfänger:
☐ Stehe im Verzeichnis: ~/mac-home
☐ Führe Status aus: ./sync-home-content.sh status
☐ Lese die Zusammenfassung sorgfältig
☐ Führe mit --dry-run aus: ./sync-home-content.sh [modus] --dry-run
☐ Stimmst du mit den Änderungen überein? (JA → nächster Schritt)
☐ Führe ohne --dry-run aus: ./sync-home-content.sh [modus]
☐ Prüfe Logs: tail .sync-home-content.log
☐ Backups prüfen: ls -la .sync-backups/
═══════════════════════════════════════════════════════════════════════════════
⚡ HÄUFIGE SZENARIEN:
1️⃣ Neue dotfiles lokal bearbeitet → Repo speichern
./sync-home-content.sh status # Was wurde geändert?
./sync-home-content.sh pull --dry-run # Trockentest
./sync-home-content.sh pull # Echte Sync
cd home-content && git commit -am "Update" && git push
2️⃣ Git-Update von Team → Lokal anwenden
git pull # Repository updaten
./sync-home-content.sh push --dry-run # Trockentest
./sync-home-content.sh push # Echte Sync
source ~/.zshrc # (bei .zshrc) neuladen
3️⃣ "Ich weiß nicht was los ist" (safest)
./sync-home-content.sh sync --dry-run -v # Ausführlich sehen
./sync-home-content.sh sync # Bidirektional lösen
4️⃣ Ich habe versehentlich was kaputt gemacht
ls -lh .sync-backups/ # Backup finden
cp .sync-backups/DATEI.*.backup home-content/DATEI
./sync-home-content.sh push # Restore
═══════════════════════════════════════════════════════════════════════════════
❓ FRAGEN:
Q: Verliere ich lokale Änderungen?
A: NEIN! Es wird immer ein Backup erstellt bevor überschrieben wird.
.sync-backups/ enthält die alten Versionen.
Q: Was ist der Unterschied pull vs push?
A: PULL = Home → Repo (lokale Änderungen ins Repository)
PUSH = Repo → Home (Repository ins lokale Home-Dir)
Q: Kann ich mehrere Dateien gleichzeitig mit --dry-run testen?
A: JA! --dry-run tut nix, du kannst mehrmals hintereinander testen.
Q: Wie oft sollte ich cleanup laufen lassen?
A: Monatlich ist sinnvoll. Script löscht nur Backups >30 Tage.
Q: Kann ich es automatisieren (Cron)?
A: JA! Aber nutze `sync` mode im non-interactive (Standard).
Im .sync-backups musst du selbst aufräumen.
═══════════════════════════════════════════════════════════════════════════════
🔗 WEITERE INFOS:
Detaillierte Doku: SYNC-STRATEGY.md
Logs: .sync-home-content.log
Hilfe: ./sync-home-content.sh -h
═══════════════════════════════════════════════════════════════════════════════
🚀 READY? Let's go:
cd ~/mac-home
./sync-home-content.sh status
EOF
+227
View File
@@ -0,0 +1,227 @@
# mac-home Synchronisierungs-Toolset
Drei hilfreiche Werkzeuge um deine Dotfiles (`~/.zshrc`, `~/.gitconfig`, etc.) zwischen deinem Home-Directory und diesem Repository zu synchronisieren.
## 📦 Dateien
| Datei | Größe | Zweck |
|-------|-------|-------|
| **`sync-home-content.sh`** | 17 KB | Hauptscript mit 6 Synchronisierungs-Modi |
| **`SYNC-STRATEGY.md`** | 10 KB | Ausführliche Dokumentation & Best Practices |
| **`QUICK-START.sh`** | 6 KB | Quick-Start Guide (diesen hier lesen!) |
---
## 🚀 Schnellstart
```bash
cd ~/mac-home
# 1. Status anschauen
./sync-home-content.sh status
# 2. Mit --dry-run testen (KEINE Änderungen)
./sync-home-content.sh sync --dry-run
# 3. Echte Synchronisierung
./sync-home-content.sh sync
```
---
## 🎯 Die 6 Modi
### 1. **STATUS** — Nur Information
Zeigt welche Dateien geändert wurden (ohne zu ändern).
```bash
./sync-home-content.sh status
```
### 2. **PUSH** — Repo → Home
Kopiert vom Repository ins lokale Home-Directory.
**Nutze wenn:** Git-Update vorhanden.
```bash
./sync-home-content.sh push
```
### 3. **PULL** — Home → Repo
Kopiert vom Home-Directory ins Repository.
**Nutze wenn:** Lokal Dateien bearbeitet.
```bash
./sync-home-content.sh pull
```
### 4. **SYNC** — Bidirektional
Intelligente 2-Wege Synchronisierung.
**Nutze wenn:** Du unsicher bist, was verändert wurde.
```bash
./sync-home-content.sh sync
```
### 5. **CLEANUP** — Alte Backups löschen
Entfernt Backups älter als 30 Tage.
```bash
./sync-home-content.sh cleanup
```
### 6. **LIST** — Verwaltete Dateien
Zeigt alle Dateien, die versioniert sind.
```bash
./sync-home-content.sh list
```
---
## 🛡️ Sicherheitsfeatures
✅ **Backups:** Vor jeder Änderung wird ein Backup erstellt (`.sync-backups/`)
✅ **Dry-Run:** Mit `--dry-run` testen ohne zu ändern
✅ **Checksummen:** Content-basierter Vergleich (md5sum, nicht Timestamp)
✅ **Logs:** Alles protokolliert in `.sync-home-content.log`
✅ **Smart Conflict-Handling:** Neuere Version gewinnt automatisch (oder interaktiv)
---
## 💡 Typische Workflows
### Scenario 1: Lokal `.zshrc` bearbeitet
```bash
./sync-home-content.sh status # "≠ geändert im Home: .zshrc"
./sync-home-content.sh pull --dry-run # Test
./sync-home-content.sh pull # Sync ins Repo
git -C home-content commit -am "Update .zshrc"
git -C home-content push
```
### Scenario 2: Git-Pull → Home updaten
```bash
git pull # Repository updaten
./sync-home-content.sh push --dry-run # Test
./sync-home-content.sh push # Sync ins Home
source ~/.zshrc # (bei .zshrc reload)
```
### Scenario 3: "Weiß nicht was los ist"
```bash
./sync-home-content.sh sync --dry-run -v # Ausführlich sehen
./sync-home-content.sh sync # Bi-direktional sync
```
---
## 📋 Optionen
| Flag | Effekt | Beispiel |
|------|--------|---------|
| `-d, --dry-run` | Zeige nur, ohne zu ändern | `./sync status --dry-run` |
| `-v, --verbose` | Detaillierter Output | `./sync status -v` |
| `-i, --interactive` | Frage bei Konflikten | `./sync sync --interactive` |
| `--no-backup` | Keine Backups erstellen | `./sync push --no-backup` |
| `-h, --help` | Zeige Hilfe | `./sync -h` |
---
## 📚 Dokumentation
- **Quick-Start:** `./QUICK-START.sh` (ausgeben)
- **Detaillierte Docs:** Lies `SYNC-STRATEGY.md`
- **Logs:** `cat .sync-home-content.log`
---
## 🆘 Fehlerbehandlung
### Backup versehentlich gelöscht?
```bash
# Schaue in .sync-backups nach
ls -lh .sync-backups/
# Restore
cp .sync-backups/.gitconfig.20260928_150000.backup home-content/.gitconfig
```
### Falsche Synchronisierung?
```bash
# Checksum-Mismatch? Das sind die gültigen Einträge:
cd home-content && git ls-files
```
### Script zu langsam?
- Normal für ~14 Dateien < 1 Sek (md5sum overhead minimal)
- Bei vielen Dateien: `seq-Verarbeitung` ist bewusst, nicht parallelisierbar
---
## ⚙️ Erweiterte Nutzung
### Alias für schnellen Zugriff
```bash
# In ~/.zshrc hinzufügen:
alias synchome="~/mac-home/sync-home-content.sh"
alias synchome-status="~/mac-home/sync-home-content.sh status"
alias synchome-pull="~/mac-home/sync-home-content.sh pull --dry-run && ~/mac-home/sync-home-content.sh pull"
```
### Cron-Job für regelmäßigen Sync
```bash
# Alle 2 Stunden
0 */2 * * * cd ~/mac-home && ./sync-home-content.sh sync >> /tmp/sync-home.log 2>&1
```
---
## 🔍 Strategie: Inhalt vs. Timestamp?
Das Script nutzt **md5sum für Erkennung** + **Timestamp für Konflikt-Auflösung**:
| Aspekt | Methode | Grund |
|--------|---------|-------|
| Änderung erkennen | md5sum (Content) | Zuverlässig, Zeitzone-unabhängig |
| Konflikt lösen | Timestamp (mtime) | Welche Version ist neuerer? |
| Nur in Repo? | git ls-files | Tracking nur versionierter Dateien |
---
## ✅ Best Practices
**IMMER TUN:**
- ✓ Vor kritischen Änderungen `status` checken
- ✓ Mit `--dry-run` testen bevor echte Sync
- ✓ Logs regelmäßig prüfen: `tail .sync-home-content.log`
- ✓ Alte Backups mit `cleanup` entfernen (monatlich)
**NICHT TUN:**
- ✗ `--no-backup` ohne wichtigen Grund nutzen
- ✗ `push` als Standard-Modus (zu aggressiv)
- ✗ Mehrere Sync-Prozesse parallel laufen lassen
- ✗ `.sync-backups/` von Hand löschen
---
## 📖 Weitere Ressourcen
- Detaillierte Erklärung der Modi: `SYNC-STRATEGY.md` (5 min Lesedauer)
- Troubleshooting: `SYNC-STRATEGY.md` → Abschnitt "Troubleshooting"
- Change-Management Strategie: `SYNC-STRATEGY.md` → Abschnitt "Change-Management"
---
## 🤖 Was das Script tut
1. Liest alle in `git ls-files` registrierten Dateien
2. Vergleicht deren Checksum zwischen Repo und Home
3. Erstellt automatisch Backups bei Änderungen
4. Synchronisiert basierend auf gewähltem Modus
5. Protokolliert alles in `.sync-home-content.log`
6. Entfernt alte Backups (> 30 Tage mit `cleanup`)
---
## 💬 Fragen?
Lesen Sie `SYNC-STRATEGY.md` - fast alle Fragen sind dort beantwortet!
---
**Viel Erfolg beim Synchronisieren! 🎉**
+423
View File
@@ -0,0 +1,423 @@
# Synchronisierungs-Strategie für home-content
## Überblick
Das Script `sync-home-content.sh` synchronisiert Dateien zwischen dem Git-Repository (`home-content/`) und dem echten Home-Verzeichnis (`$HOME`).
**Schlüsselprinzipien:**
- ✓ Nur Dateien sync, die in `git ls-files` versioniert sind
- ✓ Content-basierte Erkennung via md5sum (verlässlicher als Timestamps)
- ✓ Automatische Backups bei Änderungen (`.sync-backups/`)
- ✓ Mehrere Modi für verschiedene Szenarien
- ✓ Sicher via Dry-Run vor echten Änderungen
---
## Modi & Anwendungsfälle
### 1. **STATUS** (Standard) — Nur Information
```bash
./sync-home-content.sh status
./sync-home-content.sh status -v # verbose mit Checksummen
```
**Was es tut:**
- Vergleicht alle Dateien im Repo mit Home-Dir
- Zeigt Unterschiede via md5sum
- **Ändert nichts**
**Ausgabe-Bedeutungen:**
| Symbol | Bedeutung |
|--------|-----------|
| ✓ | Datei ist identisch |
| ≠ | Datei geändert im Home-Dir |
| ✚ | Datei nur im Repo (nicht im Home) |
**Use-Case:** Am Anfang, um zu sehen, was sich geändert hat
---
### 2. **PUSH** — Repo → Home-Dir
```bash
./sync-home-content.sh push --dry-run # Erst testen
./sync-home-content.sh push # Echte Synchronisierung
```
**Was es tut:**
- Kopiert Dateien vom Repo ins Home-Dir
- Überschreibt lokale Änderungen ohne zu fragen
- Erstellt Backup von geänderten lokalen Dateien (`.sync-backups/`)
- Neue Dateien: einfach kopieren ohne Backup
**Ablauf:**
```
1. Status 0 (identisch): unverändert
2. Status 3 (geändert): Backup Home → Repo → Home (Repo gewinnt)
3. Status 4 (nur Repo): Kopieren ohne Backup
```
**Use-Case:**
- Repo-Dateien sind authoritative Version (z.B. nach Git-Pull)
- Lokale Änderungen waren Fehlgriffe
- Schnelle Synchronisierung nach `.gitconfig` Update
---
### 3. **PULL** — Home-Dir → Repo
```bash
./sync-home-content.sh pull --dry-run # Erst testen
./sync-home-content.sh pull # Echte Synchronisierung
```
**Was es tut:**
- Kopiert veränderte Dateien vom Home-Dir ins Repo
- Nur Updates bei geänderten Dateien
- Erstellt Backup der Repo-Dateien vor Update
- Nur im Home existierende Dateien: ignoriert
**Ablauf:**
```
1. Status 0 (identisch): unverändert
2. Status 3 (geändert): Backup Repo → Home → Repo (Home gewinnt)
3. Status 4 (nur Repo): ignoriert (nicht im Home)
```
**Use-Case:**
- Lokale Änderungen sind wichtig (z.B. neue `.gitconfig`)
- Diese sollen ins Repo → für andere Maschinen verfügbar machen
- Git-Commit erforderlich nach Pull
---
### 4. **SYNC** — Bidirektional (Klug)
```bash
./sync-home-content.sh sync --dry-run # Testen
./sync-home-content.sh sync # Auto-Konflikt-Lösung
./sync-home-content.sh sync --interactive # Fragen bei Konflikten
```
**Was es tut:**
- Bidirektionale Synchronisierung
- **Automatisch:** Neuere Datei gewinnt (via Timestamp)
- **Interaktiv:** Benutzer wählt bei jedem Konflikt
**Konflikt-Handling (Non-Interactive):**
```
Wenn beide unterschiedlich:
- Home neuerer (mtime) → Home gewinnt (→ Repo)
- Repo neuerer (mtime) → Repo gewinnt (→ Home)
```
**Konflikt-Handling (Interactive):**
```
Optionen für jede konflikt-Datei:
1) Nehme Repo-Version (→ Home überschreiben)
2) Nehme Home-Version (← Repo überschreiben)
3) Behalte beide (Home als Backup aufbewahren)
4) Überspringe diese Datei
```
**Beispiel Workflow:**
```bash
# 1. Anschauen, was zu sync ist
./sync-home-content.sh status -v
# 2. Sicher testen
./sync-home-content.sh sync --dry-run
# 3. Interaktiv bei Konflikten
./sync-home-content.sh sync --interactive
# 4. Backups prüfen
ls -lh .sync-backups/
```
**Use-Case:**
- Routine-Sync mit potentiellen lokalen Änderungen
- Sicherheit durch Backups
- Smart: neuere Versionen gewinnen automatisch
---
### 5. **CLEANUP** — Alte Backups löschen
```bash
./sync-home-content.sh cleanup
```
**Was es tut:**
- Löscht Backups älter als 30 Tage
- Spart Speicherplatz
**Backup-Struktur:**
```
.sync-backups/
├── .gitconfig.20260928_150000.backup
├── .gitconfig.20260925_140000.backup ← älter als 30 Tage → löschen
├── .zshrc.20260927_180000.backup
└── ...
```
---
### 6. **LIST** — Zeige verwaltete Dateien
```bash
./sync-home-content.sh list
```
Gibt alle Dateien aus, die versioniert sind (`git ls-files`).
---
## Change-Management Strategie
### Inhalt vs. Timestamp?
Das Script nutzt **Content-Vergleich (md5sum)** als Primär-Verfahren:
| Ansatz | Vorteile | Nachteile |
|--------|----------|----------|
| **Checksum (md5)** | Erkennt wirkliche Änderungen, Zeitzone-unabhängig | Minimal langsamer |
| **Timestamp** | Schnell | Falsch-Positive bei cp/rsync, Zeitzone-sensibel |
**Strategie:**
1. **Erkennung:** md5sum → schnelle, zuverlässige Erkennung echter Änderungen
2. **Konflikt-Auflösung:** Timestamp (`mtime`) → welche Version ist neuerer
---
## Backup-Strategie
### Automatische Backups
- **Bei Push:** Backup der lokalen (überschriebenen) Datei vor Update
- **Bei Pull:** Backup der Repo-Datei vor Update
- **Bei Sync:** Backup je nach Konflikt-Lösung
- **Deaktivierbar:** `--no-backup` Option
### Backup-Verzeichnis
```bash
.sync-backups/
├── .gitconfig.20260928_150000.backup # Timestamp = YYYYMMDD_HHMMSS
├── .gitconfig.20260925_200000.backup
└── .zshrc.20260927_120000.backup
```
### Restore aus Backup
```bash
# Beispiel: .gitconfig wiederherstellen
cp .sync-backups/.gitconfig.20260928_150000.backup home-content/.gitconfig
```
---
## Workflow-Beispiele
### Scenario 1: Neue `.gitconfig` lokal
```bash
# 1. Bearbeite lokal im Home
vim ~/.gitconfig
# 2. Check Status
./sync-home-content.sh status
# Output: ≠ geändert im Home: .gitconfig
# 3. Ins Repo synchronisieren
./sync-home-content.sh pull --dry-run
# Output: ← update: .gitconfig (Home → Repo)
./sync-home-content.sh pull
# Output: Backup erstellt: .gitconfig (vor Pull) → .sync-backups/.gitconfig.20260928_XXX
# 4. Git-Commit
cd home-content
git diff .gitconfig
git add .gitconfig
git commit -m "chore: update .gitconfig"
git push
```
### Scenario 2: Repo-Update von anderer Maschine
```bash
# 1. Remote fetch (Git Pull)
git pull origin main
# 2. Check Status
./sync-home-content.sh status
# Output: ≠ geändert im Home: .zshrc
# 3. Repo-Version ins Home
./sync-home-content.sh push --dry-run
# Output: → update: .zshrc (Repo → Home) [lokale Änderung wird überschrieben]
./sync-home-content.sh push
# Output: Backup erstellt: .zshrc (vor Push) → .sync-backups/.zshrc.20260928_XXX
# 4. Neue Datei aktiv (Shell reload bei .zshrc)
source ~/.zshrc
```
### Scenario 3: Bidirektional mit Konflikten
```bash
./sync-home-content.sh sync --interactive
# Für jede Konflikt-Datei: interaktiv wählen
# Oder Auto-Modus (neuere gewinnt)
./sync-home-content.sh sync
```
---
## Optionen Referenz
| Option | Effekt | Beispiel |
|--------|--------|---------|
| `-d`, `--dry-run` | Zeige nur, ohne zu ändern | `./sync status --dry-run` |
| `-v`, `--verbose` | Debug-Output (mit Checksummen) | `./sync status -v` |
| `-i`, `--interactive` | Frage bei Konflikten (nur sync) | `./sync sync --interactive` |
| `--no-backup` | Keine Backups erstellen | `./sync push --no-backup` |
| `-h`, `--help` | Zeige Hilfe | `./sync -h` |
**Kombinierbar:**
```bash
./sync-home-content.sh sync --dry-run --verbose --interactive
```
---
## Logs & Debugging
### Log-Datei
Alle Operationen werden protokolliert in `.sync-home-content.log`:
```bash
tail -f .sync-home-content.log
```
### Verbose Debug-Output
```bash
./sync-home-content.sh status -v
```
Output zeigt:
- Checksummen für jede Datei
- Genaue Änderungstypen
- Schritt-für-Schritt Durchsatz
---
## Best Practices
### ✓ TUN:
1. **Vor kritischen Änderungen:** `status` checken
2. **Vor echtem Sync:** `--dry-run` testen
3. **Periodisch Backups prüfen:** `ls -lh .sync-backups/`
4. **Nach Push:** Git-Commit & Push (falls Repo-Änderungen)
5. **Verbose nutzen:** Bei Unsicherheiten `-v` Option
### ✗ NICHT:
1. `--no-backup` ohne Grund nutzen (Backups sind Rettungsanker)
2. `push` Mode als Standard (zu aggressiv)
3. Logs löschen ohne Archivierung
4. Alte Backups manuell löschen (dafür `cleanup`)
5. Mehrere Sync-Prozesse parallel laufen lassen
---
## Troubleshooting
### Problem: "git: command not found"
```bash
# Prüfe ob in Repository:
pwd
# Sollte: /Users/u241100/mac-home
# Prüfe git Status:
git status
```
### Problem: "Permission denied" auf Backup
```bash
# Prüfe .sync-backups Permissions:
ls -ld .sync-backups
chmod 755 .sync-backups
chmod 644 .sync-backups/*
```
### Problem: Datei wurde falsch überschrieben
```bash
# 1. Finde richtiges Backup
ls .sync-backups/ | grep dateiname
# 2. Restore
cp .sync-backups/dateiname.YYYYMMDD_HHMMSS.backup home-content/dateiname
# 3. Ggf. manual zurückschreiben nach Home
cp home-content/dateiname ~/dateiname
```
### Problem: Script ist zu langsam
- Meist normal (für 14 Dateien < 1 Sek)
- Bei Verzeichniss-Inhalten mit vielen Dateien: md5sum ist minimal-overhead
---
## Integration in Workflow
### Alias für schnellen Zugriff
```bash
# In ~/.zshrc hinzufügen:
alias synchome="~/mac-home/sync-home-content.sh"
alias synchome-status="~/mac-home/sync-home-content.sh status"
alias synchome-pull="~/mac-home/sync-home-content.sh pull --dry-run && ~/mac-home/sync-home-content.sh pull"
```
### Pre-Commit Hook (Optional)
```bash
# .git/hooks/pre-commit
#!/bin/bash
~/mac-home/sync-home-content.sh status
# Bricht ab, wenn Unterschiede existieren
```
### Cron-Job für regelmäßigen Sync
```bash
# Jeden Tag um 2 Uhr nachts
0 2 * * * cd ~/mac-home && ./sync-home-content.sh sync >> /tmp/sync-home.log 2>&1
```
---
## Zusammenfassung Konflikt-Handling
| Szenario | Pull | Push | Sync (Auto) | Sync (Interactive) |
|----------|------|------|-------------|-------------------|
| Datei identisch | — | — | — | — |
| Nur Home geändert | Home gewinnt | — | neuere (Home) gewinnt | Benutzer wählt |
| Nur Repo geändert | — | Repo gewinnt | neuere (Repo) gewinnt | Benutzer wählt |
| Beide geändert | — | — | neuere (Timestamp) gewinnt | Benutzer wählt (4 Optionen) |
| Nur im Repo | ignoriert | kopiert | kopiert | kopiert |
---
## Checkliste für neuen Rechner
```bash
cd ~/mac-home
# 1. Status prüfen
./sync-home-content.sh status
# 2. Neue Dateien trocken kopieren
./sync-home-content.sh push --dry-run
# 3. Echte Synchronisierung
./sync-home-content.sh push
# 4. Backups überprüfen (sollten leer sein)
ls -la .sync-backups/
# 5. Log prüfen
tail .sync-home-content.log
```
Fertig! Home-Verzeichnis ist jetzt mit Repository sync.
+539
View File
@@ -0,0 +1,539 @@
#!/bin/bash
################################################################################
# Synchronisierungs-Script: mac-home/home-content <-> Home-Directory
#
# Synchronisiert nur die Dateien, die im Git-Repo versioniert sind.
# Unterstützt mehrere Modi mit Konflikt-Handling.
#
# Strategie bei Changes:
# - Content-basiert via md5sum (verlässlicher als Timestamp)
# - Automatische Backups bei lokalen Änderungen
# - Mehrere Modi für verschiedene Szenarien
################################################################################
set -euo pipefail
# Farben
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Verzeichnisse
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_DIR="$SCRIPT_DIR/home-content"
HOME_DIR="$HOME"
BACKUP_DIR="$SCRIPT_DIR/.sync-backups"
LOG_FILE="$SCRIPT_DIR/.sync-home-content.log"
# Konfiguration
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
DRY_RUN=false
VERBOSE=false
INTERACTIVE=false
AUTO_BACKUP=true
################################################################################
# Hilfsfunktionen
################################################################################
log() {
echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $*" | tee -a "$LOG_FILE"
}
error() {
echo -e "${RED}[ERROR]${NC} $*" >&2 | tee -a "$LOG_FILE"
}
success() {
echo -e "${GREEN}[OK]${NC} $*" | tee -a "$LOG_FILE"
}
warn() {
echo -e "${YELLOW}[WARN]${NC} $*" | tee -a "$LOG_FILE"
}
verbose() {
[[ "$VERBOSE" == true ]] && echo -e "${BLUE}[DEBUG]${NC} $*" | tee -a "$LOG_FILE"
}
################################################################################
# Berechne md5sum für eine Datei (mit Fallback für verschiedene OSs)
################################################################################
get_checksum() {
local file="$1"
if [[ -f "$file" ]]; then
if command -v md5 &> /dev/null; then
# macOS
md5 -q "$file"
elif command -v md5sum &> /dev/null; then
# Linux
md5sum "$file" | awk '{print $1}'
else
error "Weder md5 noch md5sum verfügbar"
return 1
fi
fi
}
################################################################################
# Erstelle Backup einer Datei
################################################################################
backup_file() {
local src="$1"
local desc="$2"
[[ ! -f "$src" ]] && return 0
mkdir -p "$BACKUP_DIR"
local backup_file="$BACKUP_DIR/$(basename "$src").$TIMESTAMP.backup"
cp "$src" "$backup_file"
log "Backup erstellt: $desc → $backup_file"
}
################################################################################
# Status einer Datei prüfen
################################################################################
# Vergleicht Datei im Repo mit Home-Dir
# Returns:
# 0 = identisch
# 1 = nur in Repo
# 2 = nur im Home
# 3 = unterschiedlicher Inhalt
# 4 = nur im Repo, nicht im Home
check_file_status() {
local repo_file="$1"
local home_file="$2"
local repo_name=$(basename "$repo_file")
if [[ ! -f "$repo_file" ]]; then
return 1 # nicht im Repo
fi
if [[ ! -f "$home_file" ]]; then
return 4 # nur im Repo
fi
local repo_sum=$(get_checksum "$repo_file")
local home_sum=$(get_checksum "$home_file")
if [[ "$repo_sum" == "$home_sum" ]]; then
return 0 # identisch
else
return 3 # unterschiedlich
fi
}
################################################################################
# Modus: STATUS
# Zeigt Unterschiede zwischen Repo und Home
################################################################################
mode_status() {
log "Status: Vergleiche Repo mit Home-Dir..."
local identical=0
local modified=0
local repo_only=0
while IFS= read -r file; do
local repo_file="$REPO_DIR/$file"
local basename=$(basename "$file")
local home_file="$HOME_DIR/$basename"
check_file_status "$repo_file" "$home_file"
local status=$?
case $status in
0)
verbose "✓ identisch: $basename"
((identical++))
;;
3)
warn "≠ geändert im Home: $basename"
if [[ "$VERBOSE" == true ]]; then
echo " Repo: $(get_checksum "$repo_file")"
echo " Home: $(get_checksum "$home_file")"
fi
((modified++))
;;
4)
warn "✗ nur im Repo: $basename (nicht im Home)"
((repo_only++))
;;
esac
done < <(cd "$REPO_DIR" && git ls-files)
echo ""
success "Status-Zusammenfassung:"
echo " Identisch: $identical"
echo " Geändert: $modified"
echo " Nur im Repo: $repo_only"
}
################################################################################
# Modus: PULL
# Home-Dir → Repo (kopiere geänderte Dateien von Home ins Repo)
################################################################################
mode_pull() {
log "Pull: Synchronisiere geänderte Dateien von Home-Dir ins Repo..."
local updated=0
local skipped=0
while IFS= read -r file; do
local repo_file="$REPO_DIR/$file"
local basename=$(basename "$file")
local home_file="$HOME_DIR/$basename"
check_file_status "$repo_file" "$home_file"
local status=$?
case $status in
0)
verbose "⊙ unverändert: $basename"
;;
3)
warn "← update: $basename (Home → Repo)"
if [[ "$DRY_RUN" == false ]]; then
[[ "$AUTO_BACKUP" == true ]] && backup_file "$repo_file" "$basename (vor Pull)"
cp "$home_file" "$repo_file"
((updated++))
fi
;;
4)
verbose "⊘ ausgelassen: $basename (nicht im Home)"
((skipped++))
;;
esac
done < <(cd "$REPO_DIR" && git ls-files)
success "Pull abgeschlossen: $updated aktualisiert, $skipped ausgelassen"
}
################################################################################
# Modus: PUSH
# Repo → Home (kopiere Repo-Dateien ins Home-Dir)
################################################################################
mode_push() {
log "Push: Synchronisiere Repo-Dateien ins Home-Dir..."
local updated=0
local backed_up=0
local skipped=0
while IFS= read -r file; do
local repo_file="$REPO_DIR/$file"
local basename=$(basename "$file")
local home_file="$HOME_DIR/$basename"
check_file_status "$repo_file" "$home_file"
local status=$?
case $status in
0)
verbose "⊙ unverändert: $basename"
;;
3)
warn "→ update: $basename (Repo → Home) [lokale Änderung wird überschrieben]"
if [[ "$DRY_RUN" == false ]]; then
if [[ "$AUTO_BACKUP" == true ]]; then
backup_file "$home_file" "$basename (vor Push)"
((backed_up++))
fi
cp "$repo_file" "$home_file"
((updated++))
fi
;;
4)
verbose "✚ neu: $basename (Repo → Home)"
if [[ "$DRY_RUN" == false ]]; then
cp "$repo_file" "$home_file"
((updated++))
fi
;;
esac
done < <(cd "$REPO_DIR" && git ls-files)
success "Push abgeschlossen: $updated kopiert, $backed_up Backups, $skipped ausgelassen"
}
################################################################################
# Modus: SYNC (bidirektional mit Konflikt-Handling)
################################################################################
mode_sync() {
log "Sync: Bidirektionale Synchronisierung..."
local updated=0
local backed_up=0
local conflicts=0
while IFS= read -r file; do
local repo_file="$REPO_DIR/$file"
local basename=$(basename "$file")
local home_file="$HOME_DIR/$basename"
check_file_status "$repo_file" "$home_file"
local status=$?
case $status in
0)
verbose "⊙ unverändert: $basename"
;;
3)
# Konflikt: beide unterschiedlich
if [[ "$INTERACTIVE" == true ]]; then
echo ""
warn "KONFLIKT: $basename unterscheidet sich"
echo " Repo Checksum: $(get_checksum "$repo_file")"
echo " Home Checksum: $(get_checksum "$home_file")"
echo ""
echo "Optionen:"
echo " 1) Nehme Repo-Version (→ Home überschreiben)"
echo " 2) Nehme Home-Version (← Repo überschreiben)"
echo " 3) Behalte beide (Home-Version wird gebackupt)"
echo " 4) Überspringe diese Datei"
read -p "Wahl [1-4]: " choice
case $choice in
1)
[[ "$DRY_RUN" == false ]] && {
backup_file "$home_file" "$basename (Konflikt-Lösung)"
cp "$repo_file" "$home_file"
((updated++))
}
;;
2)
[[ "$DRY_RUN" == false ]] && {
backup_file "$repo_file" "$basename (Konflikt-Lösung)"
cp "$home_file" "$repo_file"
((updated++))
}
;;
3)
[[ "$DRY_RUN" == false ]] && backup_file "$home_file" "$basename (Konflikt-Aufbewahrung)"
((backed_up++))
;;
4)
((conflicts++))
;;
esac
else
# Non-interactive: Home gewinnt (lokal neuere Version wird bevorzugt)
local repo_mtime=$(stat -f%m "$repo_file" 2>/dev/null || stat -c%Y "$repo_file")
local home_mtime=$(stat -f%m "$home_file" 2>/dev/null || stat -c%Y "$home_file")
if (( home_mtime > repo_mtime )); then
verbose "← konflikt (Home neuerer): $basename → Repo wird aktualisiert"
if [[ "$DRY_RUN" == false ]]; then
backup_file "$repo_file" "$basename (Konflikt)"
cp "$home_file" "$repo_file"
((updated++))
fi
else
verbose "→ konflikt (Repo neuerer): $basename → Home wird aktualisiert"
if [[ "$DRY_RUN" == false ]]; then
backup_file "$home_file" "$basename (Konflikt)"
cp "$repo_file" "$home_file"
((updated++))
fi
fi
fi
;;
4)
verbose "✚ neu: $basename (Repo → Home)"
if [[ "$DRY_RUN" == false ]]; then
cp "$repo_file" "$home_file"
((updated++))
fi
;;
esac
done < <(cd "$REPO_DIR" && git ls-files)
success "Sync abgeschlossen: $updated synchronisiert, $backed_up Backups, $conflicts Konflikte"
}
################################################################################
# Modus: CLEANUP
# Entferne alte Backup-Dateien (älter als 30 Tage)
################################################################################
mode_cleanup() {
log "Cleanup: Entferne alte Backups (älter als 30 Tage)..."
if [[ ! -d "$BACKUP_DIR" ]]; then
success "Kein Backup-Verzeichnis vorhanden"
return 0
fi
local removed=0
while IFS= read -r backup_file; do
rm -f "$backup_file"
verbose "Gelöscht: $backup_file"
((removed++))
done < <(find "$BACKUP_DIR" -type f -mtime +30)
success "Cleanup abgeschlossen: $removed alte Backups gelöscht"
}
################################################################################
# Modus: LIST
# Liste alle verwalteten Dateien auf
################################################################################
mode_list() {
log "Liste alle verwalteten Dateien:"
echo ""
cd "$REPO_DIR" && git ls-files | while read -r file; do
echo " • $file"
done
}
################################################################################
# Hilfefunktion
################################################################################
show_help() {
cat << EOF
Verwendung: $0 [MODE] [OPTIONS]
MODI:
status Zeige Unterschiede zwischen Repo und Home-Dir (Standard)
pull Synchronisiere von Home-Dir ins Repo (Home → Repo)
push Synchronisiere vom Repo ins Home-Dir (Repo → Home)
sync Bidirektionale Synchronisierung mit Konflikt-Handling
cleanup Entferne alte Backups (älter als 30 Tage)
list Liste alle verwalteten Dateien auf
OPTIONEN:
-d, --dry-run Zeige nur Änderungen, ohne zu modifizieren
-v, --verbose Verbose Output (DEBUG)
-i, --interactive Interaktive Konflikte lösen (nur für sync)
--no-backup Keine automatischen Backups erstellen
-h, --help Diese Hilfe anzeigen
BEISPIELE:
# Status anzeigen
$0 status
# Von Home ins Repo synchronisieren (Trockentest)
$0 pull --dry-run
# Bidirektional mit Backup synchronisieren
$0 sync
# Interaktiv mit Konflikt-Handling
$0 sync --interactive
STRATEGIE:
• Content-basiert via md5sum (zuverlässiger als Timestamps)
• Automatische Backups in .sync-backups/ vor Änderungen
• Nur Dateien synchronisieren, die in git versioniert sind
• Logs in .sync-home-content.log
EOF
}
################################################################################
# Hauptprogramm
################################################################################
main() {
local mode="status"
# Parse Argumente
while [[ $# -gt 0 ]]; do
case $1 in
status|pull|push|sync|cleanup|list)
mode="$1"
shift
;;
-d|--dry-run)
DRY_RUN=true
shift
;;
-v|--verbose)
VERBOSE=true
shift
;;
-i|--interactive)
INTERACTIVE=true
shift
;;
--no-backup)
AUTO_BACKUP=false
shift
;;
-h|--help)
show_help
exit 0
;;
*)
error "Unbekannte Option: $1"
show_help
exit 1
;;
esac
done
# Validierungen
if [[ ! -d "$REPO_DIR" ]]; then
error "Repo-Verzeichnis nicht gefunden: $REPO_DIR"
exit 1
fi
if ! git -C "$REPO_DIR" rev-parse --git-dir > /dev/null 2>&1; then
error "$REPO_DIR ist kein Git-Repository"
exit 1
fi
# Header
log "═══════════════════════════════════════════════════════════"
log "Modus: $mode"
[[ "$DRY_RUN" == true ]] && log "DRY-RUN: Keine Änderungen werden vorgenommen"
[[ "$INTERACTIVE" == true ]] && log "INTERAKTIV: Bei Konflikten wird nachgefragt"
log "═══════════════════════════════════════════════════════════"
# Führe Modus aus
case $mode in
status)
mode_status
;;
pull)
mode_pull
;;
push)
mode_push
;;
sync)
mode_sync
;;
cleanup)
mode_cleanup
;;
list)
mode_list
;;
*)
error "Unbekannter Modus: $mode"
show_help
exit 1
;;
esac
log "═══════════════════════════════════════════════════════════"
[[ "$DRY_RUN" == true ]] && success "DRY-RUN abgeschlossen (keine Änderungen)" || success "Abgeschlossen"
}
# Starte Script
main "$@"