Das folgende Video zeigt Installation, ersten Sync und die wichtigsten Features von git-sync-all in unter 4 Minuten.
Themen im Video:
git-sync-all ist ein Kommandozeilen-Tool, das automatisch alle Git-Repositories in einem Verzeichnisbaum synchronisiert. Ein einziger Befehl erledigt das, was sonst dutzende manuelle git-Aufrufe erfordern: uncommittete Änderungen committen, vom Remote pullen und lokale Commits pushen.
Für wen? Entwickler, die auf mehreren Maschinen arbeiten (Büro, Homeoffice, Laptop) und alle Projekte konsistent aktuell halten wollen - ohne jeden Abend manuell durch alle Repos zu iterieren.
Kein magisches Auto-Commit-Tool ohne Kontrolle. Das Tool fragt vor dem Committen nach Bestätigung (außer im
--yes-Modus). Uncommittete Änderungen werden nicht still verworfen oder ignoriert.
git fetch --tags --prune-tags)repos.yml definiert erwartete Repos pro Maschine/Gruppe. --verify prüft Vollständigkeit, zeigt Clone-Befehle für fehlende Repos und erkennt nicht-inventarisierte Repos auf der Festplatte.--issues zeigt offene GitHub Issues pro Inventar-Gruppe. Benötigt gh CLI.~/.config/git-sync-all/git check als Alias eintragbar| Komponente | Mindestversion | Hinweis |
|---|---|---|
| Bash | 4.0+ | macOS nutzt standardmäßig Bash 3.x - Update nötig (z.B. via Homebrew) |
| Git | 2.17+ | Ab 2.17 wird --prune-tags unterstützt; ältere Versionen erzeugen eine Warnung, funktionieren aber |
| GNU find | beliebig | Standard auf Linux; auf macOS via Homebrew (brew install findutils) |
GitHub CLI (gh) |
beliebig | Optional - nur für --issues benötigt. Installation: https://cli.github.com/ |
Auf macOS ist standardmäßig Bash 3.2 installiert (Apple-Lizenzbeschränkung). Mit
brew install bashwird Bash 5.x installiert. Das System-Bash unter/bin/bashbleibt unverändert.
Erstellt einen Symlink nach ~/.local/bin. Updates per git pull sind sofort aktiv - keine erneute Installation nötig:
git clone https://github.com/markus-michalski/git-sync-all.git
cd git-sync-all
make link PREFIX=$HOME/.local
Sicherstellen, dass ~/.local/bin im PATH ist (in ~/.bashrc oder ~/.zshrc):
# In ~/.bashrc hinzufuegen (falls nicht vorhanden):
export PATH="$HOME/.local/bin:$PATH"
# Danach:
source ~/.bashrc
git-sync-all --version
# git-sync-all v1.0.0
Vorteil gegenüber make install: Da nur ein Symlink auf bin/git-sync-all im Repository zeigt, werden Änderungen per git pull sofort wirksam. Das Script löst den Symlink zur Laufzeit auf und findet die lib/-Dateien automatisch im Repository.
Installiert nach /usr/local/bin - für alle Benutzer des Systems verfügbar. Die Dateien werden kopiert, d.h. nach einem git pull muss make install erneut ausgeführt werden:
git clone https://github.com/markus-michalski/git-sync-all.git
cd git-sync-all
sudo make install
Nach der Installation:
git-sync-all --version
# git-sync-all v1.0.0
Die Makefile-Installation kopiert:
bin/git-sync-all nach /usr/local/bin/git-sync-alllib/*.sh nach /usr/local/lib/git-sync-all/Bei einer Kopie-Installation muss nach jedem
git pullerneutmake install(bzw.sudo make install) ausgeführt werden, damit Änderungen wirksam werden.
Wie die System-Installation, aber nach ~/.local statt /usr/local:
git clone https://github.com/markus-michalski/git-sync-all.git
cd git-sync-all
make install PREFIX=$HOME/.local
Auch hier gilt: Nach
git pullmussmake install PREFIX=$HOME/.localerneut ausgeführt werden. Für automatische Updates istmake linkdie bessere Wahl.
Nach einer der obigen Installationsmethoden kann ein git check-Alias eingerichtet werden:
git-sync-all --setup-alias
# Ausgabe: Added 'git check' alias to ~/.gitconfig
Danach ist folgender Aufruf möglich:
git check # identisch mit git-sync-all
git check --status # identisch mit git-sync-all --status
Der Alias wird in ~/.gitconfig eingetragen und zeigt auf den absoluten Pfad der Binary.
# Symlink oder Kopie entfernen (benutzer-lokal)
make uninstall PREFIX=$HOME/.local
# System-Installation entfernen
sudo make uninstall
# Git-Alias entfernen
git config --global --unset alias.check
git-sync-all [OPTIONS] [DIRECTORY...]
Ohne Argumente werden die in SYNC_BASE_DIRS konfigurierten Verzeichnisse gescannt (Standard: ~/projekte).
Verzeichnisse können als Argumente übergeben werden, um SYNC_BASE_DIRS zu überschreiben:
# Standard-Verzeichnis aus Config
git-sync-all
# Spezifische Verzeichnisse
git-sync-all ~/arbeit ~/privat ~/oss
# Mehrere Verzeichnisse mit Optionen
git-sync-all --dry-run ~/arbeit ~/privat
| Option | Kurz | Beschreibung |
|---|---|---|
--help |
-h |
Hilfe anzeigen und beenden |
--version |
-V |
Version anzeigen und beenden |
--dry-run |
-n |
Zeigt an, was passieren würde - keine Änderungen |
--verbose |
-v |
Ausführlichkeit erhöhen (stapelbar: -vv) |
--quiet |
-q |
Nur Fehler ausgeben |
--yes |
-y |
Alle Repos automatisch bestätigen (keine Prompts) |
--config FILE |
-c |
Bestimmte Config-Datei verwenden |
--init-config |
Standard-Config am XDG-Pfad erstellen | |
--setup-alias |
git check-Alias in ~/.gitconfig eintragen |
|
--no-pull |
Pull-Schritt überspringen | |
--no-push |
Push-Schritt überspringen | |
--no-tags |
Tag-Synchronisierung überspringen | |
--no-commit |
Auto-Commit überspringen | |
--no-color |
Farbige Ausgabe deaktivieren | |
--status |
Nur Status-Tabelle anzeigen (keine Sync-Aktionen) | |
--verify |
Inventar prüfen: fehlende Repos finden, nicht-inventarisierte Repos zur Löschung anbieten | |
--issues |
Offene GitHub Issues für Inventar-Repos anzeigen | |
--inventory FILE |
Inventar-Datei angeben (Standard: XDG-Pfad) | |
--group NAME |
Nur Repos einer bestimmten Gruppe verifizieren; wiederholbar. Ohne --group wird SYNC_VERIFY_GROUP verwendet (Standard: all) |
|
--init-inventory |
Inventar-Datei am XDG-Pfad erstellen | |
--exclude PATTERN |
Repos mit diesem Muster ausschließen (wiederholbar) | |
--include PATTERN |
Nur Repos mit diesem Muster synchronisieren (wiederholbar) |
Verbosity-Stapeln:
-verhöht den Verbosity-Level um 1.-vventsprichtSYNC_VERBOSITY=3. Der--quiet-Flag setzt Verbosity auf 0 (nur Fehler).
Der häufigste Anwendungsfall: Alle konfigurierten Repos synchronisieren.
# Alle Repos in ~/projekte synchronisieren (Standard-Config)
git-sync-all
Beispiel-Ausgabe:
[INFO] git-sync-all v1.0.0
[INFO] Scanning: /home/markus/projekte
[INFO] Found 12 repositories
[INFO] invoice-management (main)
[INFO] Uncommitted changes detected
M src/Controller/InvoiceController.php
M templates/invoice/show.html.twig
? src/Service/NewService.php
Commit and push changes? [y/n/q]: y
[INFO] Committing changes...
[OK] Changes committed
[INFO] Pulling from remote...
[OK] Pulled successfully
[OK] Synced
[INFO] osticket-api-endpoints (main)
[OK] Clean (nothing to sync)
...
========================================
Synchronization Complete
========================================
Statistics:
Total repositories: 12
Clean (no changes): 9
Synced: 2
Skipped: 1
Failed: 0
[OK] All repositories synchronized successfully!
Vorschau, was passieren würde - absolut sicher, keine Änderungen:
git-sync-all --dry-run
Im Dry-Run-Modus werden alle schreibenden Git-Befehle durch [DRY-RUN] Would: git ... ersetzt:
[WARN] DRY-RUN mode (no changes will be made)
[INFO] invoice-management (main)
[DRY-RUN] Would: git add -A
[DRY-RUN] Would: git commit -m "chore: auto-sync from workstation" -m "Automatic synchronization..."
[DRY-RUN] Would: git pull --rebase origin main
[DRY-RUN] Would: git push origin main
Nur bestimmte Repos synchronisieren oder bestimmte ausschließen:
# Nur bestimmte Repos synchronisieren
git-sync-all --include invoice-management --include osticket-api-endpoints
# Vendor- und Node-Verzeichnisse ausschliessen
git-sync-all --exclude vendor --exclude node_modules
# Glob-Muster funktionieren ebenfalls
git-sync-all --include "osticket-*"
# Auch per Config-Variable möglich (Doppelpunkt als Trennzeichen)
# SYNC_INCLUDE="invoice-management:osticket-api-endpoints"
--includeund--excludewerden auf den Verzeichnisnamen des Repos angewendet (nicht den vollen Pfad). Bash-Glob-Muster werden unterstützt:*,?,[abc].
Für automatisierte Ausführung ohne interaktive Prompts:
# Alle Bestätigungen automatisch akzeptieren
git-sync-all --yes
# Fuer Cron-Jobs: quiet + yes
git-sync-all --quiet --yes
# Beispiel Crontab (taeglich um 18:00 Uhr):
# 0 18 * * * /usr/local/bin/git-sync-all --yes --quiet >> /var/log/git-sync.log 2>&1
# Nur ziehen, nichts pushen (sicheres Pull-only)
git-sync-all --no-commit --no-push --yes
Schnelle Übersicht aller Repos ohne Sync-Aktionen:
git-sync-all --status
Beispiel-Ausgabe:
REPOSITORY BRANCH DIRTY UNPUSHED UNPULLED
--------------------------------------------------------------------------------
invoice-management main 3 2 --
osticket-api-endpoints main -- -- --
osticket-api-key-wildcard main -- 1 --
mlm-gallery main -- -- --
script_collection main 7 -- --
[INFO] 5 repositories, 2 with uncommitted changes
Repos aus mehreren Basisverzeichnissen synchronisieren:
# Zwei Verzeichnisse angeben
git-sync-all ~/arbeit ~/privat
# Oder per Config (persistente Einstellung):
# SYNC_BASE_DIRS="$HOME/arbeit:$HOME/privat:$HOME/oss"
# Einzelnes Verzeichnis übergeben
git-sync-all /srv/projects
# Mit custom Config
git-sync-all --config ~/.config/git-sync-all/work.conf ~/arbeit
git-sync-all --init-config
# Erstellt ~/.config/git-sync-all/config.conf
# Oeffnet die Datei automatisch im konfigurierten Editor ($EDITOR)
Die Konfiguration ist eine einfache Shell-Datei (KEY=VALUE), die direkt gesourct wird. Das ermöglicht die Verwendung von Shell-Variablen wie $HOME:
# ~/.config/git-sync-all/config.conf
# Mehrere Verzeichnisse (Doppelpunkt-getrennt)
SYNC_BASE_DIRS="$HOME/projekte:$HOME/arbeit"
# Tiefe des Scans
SYNC_SCAN_DEPTH=3
# Repos ausschliessen (Glob-Muster, Doppelpunkt-getrennt)
SYNC_EXCLUDE="vendor:node_modules:.cache"
# Nur diese Repos synchronisieren
# SYNC_INCLUDE="my-project:other-project"
# Commit-Nachricht mit Platzhaltern
SYNC_COMMIT_MSG="chore: auto-sync from {hostname}"
SYNC_COMMIT_BODY="Automatic synchronization of uncommitted changes."
# Keine Bestaetigung erforderlich
SYNC_AUTO_CONFIRM=false
# Pull-Strategie: rebase oder merge
SYNC_PULL_STRATEGY="rebase"
# Tags synchronisieren
SYNC_TAGS=true
# Remote-Name
SYNC_REMOTE="origin"
# Farbe: auto, true, false
SYNC_COLOR="auto"
# Ausfuehrlichkeit: 0=still, 1=normal, 2=ausfuehrlich
SYNC_VERBOSITY=1
# Standard-Gruppe fuer --verify/--issues (komma-getrennt fuer mehrere)
# SYNC_VERIFY_GROUP="all"
| Variable | Standard | Beschreibung |
|---|---|---|
SYNC_BASE_DIRS |
$HOME/projekte |
Zu scannende Verzeichnisse, Doppelpunkt-getrennt |
SYNC_SCAN_DEPTH |
3 |
Maximale Scan-Tiefe für Repository-Suche |
SYNC_EXCLUDE |
(leer) | Repos ausschließen (Doppelpunkt-getrennte Glob-Muster) |
SYNC_INCLUDE |
(leer) | Nur diese Repos synchronisieren (Glob-Muster) |
SYNC_COMMIT_MSG |
chore: auto-sync from {hostname} |
Commit-Nachricht-Template |
SYNC_COMMIT_BODY |
Automatic synchronization... |
Erweiterter Commit-Body |
SYNC_AUTO_CONFIRM |
false |
Alle Repos automatisch bestätigen |
SYNC_PULL_STRATEGY |
rebase |
rebase oder merge |
SYNC_TAGS |
true |
Tags vom Remote holen und bereinigen |
SYNC_REMOTE |
origin |
Name des Remote (z.B. upstream) |
SYNC_COLOR |
auto |
auto, true oder false |
SYNC_VERBOSITY |
1 |
0=still, 1=normal, 2=ausführlich |
SYNC_INVENTORY_FILE |
(XDG-Standard) | Pfad zur Inventar-Datei (repos.yml) |
SYNC_VERIFY_GROUP |
all |
Standard-Gruppe für --verify und --issues ohne --group. Komma-getrennt für mehrere Gruppen (z.B. "public,private") |
Die Variable SYNC_COMMIT_MSG unterstützt folgende Platzhalter:
| Platzhalter | Ersetzt durch | Beispiel |
|---|---|---|
{hostname} |
Hostname der Maschine | workstation |
{date} |
Aktuelles Datum (YYYY-MM-DD) | 2026-02-24 |
{repo} |
Name des Repository-Verzeichnisses | invoice-management |
Beispiele:
# Standard
SYNC_COMMIT_MSG="chore: auto-sync from {hostname}"
# Ergibt: "chore: auto-sync from workstation"
# Mit Datum
SYNC_COMMIT_MSG="chore: auto-sync {date} from {hostname}"
# Ergibt: "chore: auto-sync 2026-02-24 from workstation"
# Mit Repo-Name
SYNC_COMMIT_MSG="chore: sync {repo} on {hostname}"
# Ergibt: "chore: sync invoice-management on workstation"
CLI-Flags > Umgebungsvariablen > Config-Datei > Eingebaute Defaults
Das bedeutet: Umgebungsvariablen können die Config-Datei überschreiben, ohne sie zu bearbeiten:
# Einmalig eine andere Basis verwenden
SYNC_BASE_DIRS="$HOME/oss" git-sync-all
# Einmalig ohne Farbe
SYNC_COLOR=false git-sync-all
# Einmalig im still-Modus
SYNC_VERBOSITY=0 git-sync-all --yes
Für unterschiedliche Szenarien können mehrere Config-Dateien gepflegt werden:
# Arbeits-Konfiguration
git-sync-all --config ~/.config/git-sync-all/work.conf
# Privat-Konfiguration
git-sync-all --config ~/.config/git-sync-all/personal.conf
# Nur-Pull-Konfiguration (z.B. fuer Server)
git-sync-all --config ~/.config/git-sync-all/readonly.conf --no-commit --no-push
Das Repository-Inventar ist eine YAML-Datei (repos.yml), die definiert, welche Repositories auf einer Maschine vorhanden sein sollen. In Kombination mit --verify wird geprüft, ob alle aufgelisteten Repos tatsächlich als Git-Verzeichnisse existieren.
Die Datei liegt standardmäßig unter dem XDG-Config-Pfad:
~/.config/git-sync-all/repos.yml
Der Pfad kann per SYNC_INVENTORY_FILE in der Config oder per --inventory FILE auf der Kommandozeile überschrieben werden.
git-sync-all --init-inventory
# Erstellt ~/.config/git-sync-all/repos.yml
# Oeffnet die Datei automatisch im Editor ($EDITOR)
Wenn bereits Repos im Scan-Verzeichnis vorhanden sind, wird das Inventar automatisch aus den gefundenen Repos generiert. Ansonsten wird die mitgelieferte Beispieldatei kopiert.
Repos werden in frei definierbaren Gruppen organisiert. Jede Gruppe enthält eine flache Liste von Repository-Verzeichnisnamen:
# Repos, die auf allen Maschinen vorhanden sein sollen
all:
- git-sync-all
- dotfiles
- script_collection
# Nur auf Arbeitsrechnern
work:
- shopware6-sepa-67
- shopware6-facebook-pixel-67
- oxid-module-gallery
# Persoenliche Projekte
personal:
- my-website
- notes
Für Third-Party-Repos, die nicht im eigenen GitHub-Account liegen, kann eine Clone-URL angegeben werden:
external:
- osticket: https://github.com/osTicket/osTicket
- oxid7: https://github.com/OXID-eSales/oxideshop_ce
Beide Formate koexistieren — - reponame für eigene Repos und - reponame: https://url für externe.
Bei
--verifywerden fehlende Repos mit konkreten Clone-Befehlen angezeigt:git clone <url>für Repos mit URL,gh repo clone <user>/<name>für eigene Repos.
Gruppennamen sind frei wählbar -
all,workundpersonalsind nur Konventionen. Man kann beliebige Namen verwenden, z.B.server,laptop,kunde-xyz. Der Standard-Gruppenname für--verifyohne--groupistallund kann mitSYNC_VERIFY_GROUPin der Config geändert werden (komma-getrennt für mehrere Gruppen).
Prüft alle Repos der Gruppe all (Standard):
git-sync-all --verify
Beispiel-Ausgabe:
[OK] git-sync-all → /home/markus/projekte/git-sync-all
[OK] dotfiles → /home/markus/projekte/dotfiles
[ERROR] script_collection → NOT FOUND
2/3 found, 1 missing
[INFO] Missing repositories:
script_collection
gh repo clone markus-michalski/script_collection ~/projekte/script_collection
[INFO] Tip: Add clone URLs in repos.yml for external repos (name: https://...)
Nur Repos einer bestimmten Gruppe verifizieren:
# Nur Arbeits-Repos prüfen
git-sync-all --verify --group work
# Nur persoenliche Repos prüfen
git-sync-all --verify --group personal
# Mehrere Gruppen (kommagetrennt)
git-sync-all --verify --group all,work
Eine andere Inventar-Datei verwenden (z.B. pro Maschine):
git-sync-all --verify --inventory ~/mein-inventar.yml
Beim Verify werden automatisch auch Repos erkannt, die auf der Festplatte existieren aber nicht in der repos.yml stehen:
git-sync-all --verify
Falls nicht-inventarisierte Repos gefunden werden:
[WARN] 2 repo(s) on disk but NOT in inventory:
old-experiment → /home/markus/projekte/old-experiment
temp-fork → /home/markus/projekte/temp-fork
Remove old-experiment from disk? (/home/markus/projekte/old-experiment) [y/n/q]: n
[INFO] Kept: old-experiment
Remove temp-fork from disk? (/home/markus/projekte/temp-fork) [y/n/q]: y
[OK] Removed: temp-fork
[OK] 1 repo(s) removed, 1 kept
Sicherheit: Der
--yes-Flag wird für die Löschung ignoriert — jedes Repo muss einzeln bestätigt werden. Im--dry-run-Modus wird nichts gelöscht. Im nicht-interaktiven Modus (Pipe/Cron) werden die Repos nur aufgelistet, nicht zur Löschung angeboten.
Die Erkennung nicht-inventarisierter Repos berücksichtigt immer alle Gruppen der
repos.yml, unabhängig vom--group-Filter. Dadurch werden Repos aus anderen Gruppen nicht fälschlich als nicht-inventarisiert gemeldet.
Mit --issues werden offene GitHub Issues für alle Repos aus dem Inventar abgefragt und als Tabelle angezeigt:
# Offene Issues aller Inventar-Repos anzeigen
git-sync-all --issues
# Nur bestimmte Gruppe
git-sync-all --issues --group public
# Mit Issue-Details (Nummern und Titel)
git-sync-all --issues --group public -v
Beispiel-Ausgabe:
REPOSITORY OPEN ISSUES
--------------------------------------------------
git-sync-all 3
dotfiles --
shopware6-sepa-67 1
script_collection not on GitHub
[WARN] 2 of 4 repos have open issues (total: 4)
Mit -v (Verbose) werden zusätzlich die einzelnen Issues aufgelistet:
REPOSITORY OPEN ISSUES
--------------------------------------------------
git-sync-all 3
#42 Add support for submodules
#38 Improve error messages for SSH failures
#15 Feature request: parallel sync
dotfiles --
ghCLI muss installiert und authentifiziert sein (gh auth login). Ohneghbricht der Befehl mit einer Fehlermeldung ab.
Das ist der Kernnutzen von git-sync-all: Alle Projekte zwischen mehreren Maschinen synchron halten.
Feierabend im Büro:
git-sync-all
# Committet und pusht alle laufenden Arbeiten
Ankunft im Homeoffice:
git-sync-all --verify # Prüfen ob alle erwarteten Repos vorhanden sind
git-sync-all # Änderungen vom Büro-PC holen
Nächster Tag im Büro:
git-sync-all
# Zieht alle Änderungen aus dem Homeoffice
Alle Maschinen bleiben synchron - ohne manuelle git pull-Aufrufe in jedem einzelnen Repository.
# ~/.config/git-sync-all/config.conf
# Alle Projektverzeichnisse
SYNC_BASE_DIRS="$HOME/projekte:$HOME/arbeit"
# Auto-Commit mit beschreibender Nachricht
SYNC_COMMIT_MSG="chore: auto-sync from {hostname} on {date}"
SYNC_COMMIT_BODY="Automatic synchronization of work-in-progress changes."
# Rebase fuer saubere History (kein Merge-Commit-Noise)
SYNC_PULL_STRATEGY="rebase"
# Nach Bestaetigung fragen (Sicherheitsnetz)
SYNC_AUTO_CONFIRM=false
Achtung bei Konflikten: Wenn auf zwei Maschinen gleichzeitig dieselbe Datei bearbeitet wurde, kann es zu Rebase- oder Merge-Konflikten kommen. Das Tool bricht dann mit
Pull failed (possible conflicts - resolve manually)ab. Der Konflikt muss manuell im betroffenen Repository gelöst werden.
Symptom:
[ERROR] Another instance is running (PID 12345). Remove /run/user/1000/git-sync-all.lock if stale.
Ursache: Eine andere Instanz von git-sync-all läuft noch, oder ein vorheriger Lauf wurde unsauber beendet (z.B. durch Kill-Signal).
Lösung:
# Pruefen, ob der Prozess wirklich noch laeuft
ps aux | grep git-sync-all
# Falls nicht: Lock-File manuell entfernen
rm /run/user/1000/git-sync-all.lock
# Alternativ (das Tool erkennt veraltete Locks automatisch beim naechsten Start)
# Einfach nochmal ausfuehren - stale locks werden automatisch entfernt
git-sync-all
Das Tool erkennt veraltete Lock-Files automatisch: Wenn die gespeicherte PID nicht mehr läuft, wird das Lock-File automatisch entfernt und der Lauf fortgesetzt.
Symptom:
[ERROR] Config error: directory not found: /home/markus/projekte (SYNC_BASE_DIRS)
Ursache: Das konfigurierte Verzeichnis existiert nicht (falscher Pfad, nicht gemountetes Laufwerk, etc.).
Lösung:
# Config pruefen
cat ~/.config/git-sync-all/config.conf | grep SYNC_BASE_DIRS
# Verzeichnis erstellen oder Pfad korrigieren
mkdir -p ~/projekte
# Oder Config aktualisieren
nano ~/.config/git-sync-all/config.conf
Symptom:
[ERROR] Pull failed (possible conflicts - resolve manually)
Ursache: Beim Pull gab es einen Merge- oder Rebase-Konflikt, weil dieselbe Stelle in einer Datei auf zwei Maschinen bearbeitet wurde.
Lösung:
# In das betroffene Repository wechseln
cd ~/projekte/mein-projekt
# Status pruefen
git status
# oder bei Rebase-Konflikt:
git rebase --status
# Konflikte in den markierten Dateien loesen
# (Dateien mit <<<<<<<, =======, >>>>>>> Markierungen bearbeiten)
nano konflikt-datei.txt
# Loesung stagen
git add konflikt-datei.txt
# Rebase fortsetzen (falls Rebase-Strategie)
git rebase --continue
# Oder Merge abschliessen (falls Merge-Strategie)
git commit
# Danach git-sync-all erneut ausfuehren
git-sync-all --include mein-projekt
Symptom:
[WARN] No Git repositories found in: /home/markus/projekte
Ursache: Entweder existieren keine Repos im Verzeichnis, oder der Scan-Pfad ist falsch konfiguriert, oder SYNC_SCAN_DEPTH ist zu gering.
Lösung:
# Manuell pruefen, ob .git-Verzeichnisse vorhanden sind
find ~/projekte -name ".git" -type d -maxdepth 4
# Scan-Tiefe erhoehen
SYNC_SCAN_DEPTH=5 git-sync-all
# Oder in Config setzen
echo 'SYNC_SCAN_DEPTH=5' >> ~/.config/git-sync-all/config.conf
Symptom: Mit --include my-project wird das Repo trotzdem nicht synchronisiert.
Ursache: Der Filter wird auf den Verzeichnisnamen angewendet, nicht auf den vollen Pfad. Außerdem werden Repos ohne konfigurierten Remote grundsätzlich übersprungen.
Lösung:
# Verzeichnisnamen des Repos pruefen
ls ~/projekte/ # Exakter Name des Verzeichnisses
# Remote-Konfiguration pruefen
cd ~/projekte/my-project
git remote -v
# Falls kein Remote konfiguriert: Remote hinzufuegen
git remote add origin https://github.com/user/my-project.git
# Oder: Das Tool explizit mit vollem Pfad aufrufen
git-sync-all ~/projekte/my-project
Symptom:
[WARN] Git version 2.15 detected. Recommend >= 2.17 for --prune-tags support.
Lösung (macOS):
# Homebrew installieren (falls nicht vorhanden)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Git aktualisieren
brew install git
# In ~/.bashrc oder ~/.zshrc sicherstellen, dass Homebrew-Git zuerst verwendet wird:
export PATH="/usr/local/bin:$PATH" # Intel Mac
export PATH="/opt/homebrew/bin:$PATH" # Apple Silicon
# Bash aktualisieren (falls noetig)
brew install bash
| Datei | Größe | Verantwortlichkeit |
|---|---|---|
bin/git-sync-all |
~90 Zeilen | Einstiegspunkt: sourct Libraries, orchestriert main() |
lib/core.sh |
~178 Zeilen | Strict Mode, Farbdefinitionen, Logging-Funktionen, Cleanup-Trap, Lock-File, Dependency-Check |
lib/config.sh |
~162 Zeilen | XDG-Config-Loading, Defaults setzen, Validierung, --init-config |
lib/cli.sh |
~229 Zeilen | Argument-Parsing (parse_args), Help-Text, Version, Alias-Setup |
lib/repo-discovery.sh |
~104 Zeilen | Repo-Suche via find, Include/Exclude-Filter (Glob-Matching), Remote-Check |
lib/git-ops.sh |
~197 Zeilen | Alle Git-Operationen in Subshells, Dry-Run-Wrapper (git_cmd) |
lib/sync.sh |
~252 Zeilen | Sync-Workflow pro Repo, Statistiken, Status-Tabelle, User-Confirmation |
lib/inventory.sh |
~340 Zeilen | YAML-Parser für repos.yml, Gruppen-Logik, Verify-Funktion, Inventar-Initialisierung |
lib/issues.sh |
~140 Zeilen | GitHub Issues-Abfrage via gh CLI, Tabellen-Ausgabe, Verbose-Details |
git-sync-all/
├── bin/
│ └── git-sync-all # Einstiegspunkt (main)
├── lib/
│ ├── core.sh # Strict mode, logging, colors, lock, cleanup
│ ├── config.sh # XDG config loading, defaults, validation
│ ├── cli.sh # Argument parsing, help text, alias setup
│ ├── repo-discovery.sh # Repo scanning, include/exclude filters
│ ├── git-ops.sh # All git operations, dry-run wrapper
│ ├── sync.sh # Sync workflow, statistics, status display
│ ├── inventory.sh # YAML inventory parser, verify logic
│ └── issues.sh # GitHub issues query via gh CLI
├── config/
│ ├── config.conf.example # Beispiel-Konfiguration
│ └── repos.yml.example # Beispiel-Inventar
├── tests/
│ └── ... # Test-Suite (129 Tests)
├── Makefile # Install/uninstall/check targets
└── README.md
Subshell-Isolation für Git-Operationen
Alle Git-Operationen in lib/git-ops.sh laufen in Subshells ((...)). Das verhindert, dass ein cd in ein Repository das Working Directory des Hauptprozesses verändert. Fehler in einem Repo brechen nicht den gesamten Lauf ab.
Strict Mode
set -euo pipefail ist in lib/core.sh aktiv. Das bedeutet: unbehandelte Fehler und undefinierte Variablen führen zum sofortigen Abbruch. Git-Operationen werden explizit mit || true oder durch Return-Code-Prüfung behandelt.
Dry-Run via Wrapper
Der git_cmd-Wrapper in lib/git-ops.sh prüft $DRY_RUN. Im Dry-Run-Modus werden schreibende Befehle nur ausgegeben, nicht ausgeführt. Lesende Operationen laufen immer (z.B. git status, git log).
Lock-File-Logik
Das Lock-File liegt in ${XDG_RUNTIME_DIR:-/tmp}/git-sync-all.lock und enthält die PID des laufenden Prozesses. Beim Start wird geprüft: Wenn das Lock existiert und die PID noch läuft, wird abgebrochen. Wenn die PID nicht mehr läuft (veraltetes Lock), wird es entfernt.
Include vs. Exclude-Priorität
Wenn SYNC_INCLUDE gesetzt ist, werden NUR Repos synchronisiert, die einem Include-Muster entsprechen. SYNC_EXCLUDE wird danach zusätzlich angewendet. Repos ohne konfigurierten Remote (SYNC_REMOTE, Standard: origin) werden grundsätzlich übersprungen.
# Alle Tests ausfuehren
make test
# Nur Lint (ShellCheck)
make lint
# Nur Format-Check (shfmt)
make format
# Alle Checks (lint + format + tests)
make check
Die Test-Suite umfasst 129 Tests in 7 Test-Dateien:
| Test-Datei | Beschreibung |
|---|---|
tests/test-cli.sh |
CLI-Argument-Parsing, Flag-Erkennung |
tests/test-config.sh |
Config-Loading, Defaults, Validierung |
tests/test-repo-discovery.sh |
Repo-Suche, Include/Exclude-Filter |
tests/test-git-ops.sh |
Git-Operationen, Dry-Run-Verhalten |
tests/test-conflict-handling.sh |
Konflikt-Erkennung und -Strategien |
tests/test-inventory.sh |
Inventar-Parsing, Gruppen-Filter, Verify-Logik |
tests/test-integration.sh |
End-to-End-Integration |
| Code | Bedeutung |
|---|---|
0 |
Alle Repositories erfolgreich synchronisiert (oder keine Änderungen nötig) |
1 |
Mindestens ein Repository konnte nicht synchronisiert werden |
Der Exit Code 1 tritt auf bei:
Kann ich git-sync-all in einem Cron-Job verwenden?
Ja. Mit --yes --quiet läuft das Tool vollständig nicht-interaktiv. Sicherstellen, dass die SSH-Keys oder Git-Credentials ohne interaktive Eingabe funktionieren (z.B. SSH-Agent, SSH-Key ohne Passphrase für automatisierte Umgebungen, oder HTTPS mit Credential-Store).
# Crontab-Beispiel: taeglich um 18:00 Uhr
0 18 * * * /usr/local/bin/git-sync-all --yes --quiet >> /var/log/git-sync-all.log 2>&1
Was passiert mit uncommitteten Änderungen, die ich NICHT committen will?
Das Tool fragt nach Bestätigung ([y/n/q]). Mit n wird das Repository übersprungen (zählt als "skipped" in der Zusammenfassung). Mit q wird der gesamte Lauf abgebrochen. Uncommittete Änderungen werden nie ohne Bestätigung committet (außer mit --yes).
Funktioniert das Tool mit privaten Repos und SSH-Keys?
Ja, das Tool nutzt die bestehende Git-Konfiguration. Wenn git pull und git push im Terminal manuell funktionieren, funktioniert auch git-sync-all. SSH-Agent-Forwarding und SSH-Key-basierte Authentifizierung werden unterstützt.
Kann ich git-sync-all nur für Pull verwenden (readonly)?
Ja:
# Nur pullen, nicht committen oder pushen
git-sync-all --no-commit --no-push
# Oder in der Config:
# SYNC_AUTO_CONFIRM=false
# (und dann immer mit 'n' antworten - aber --no-commit ist sauberer)
Was ist der Unterschied zwischen --status und einem normalen Lauf?
--status zeigt nur eine Übersichtstabelle an (Repo-Name, Branch, Anzahl uncommitteter Dateien, Anzahl nicht-gepushter Commits). Es werden keine Git-Operationen ausgeführt. Besonders nützlich für einen schnellen Überblick vor dem eigentlichen Sync.
Werden Submodule unterstützt?
Nein, derzeit nicht explizit. Submodule werden als eigenständige Repos erkannt, wenn sie ein eigenes .git-Verzeichnis haben und einen Remote konfiguriert haben. Die Submodul-Aktualisierung des Parent-Repos wird nicht automatisch ausgeführt.
Was passiert, wenn ich auf Branch feature/xyz bin statt main?
Das Tool synchronisiert immer den aktuellen Branch des Repositories. Es wechselt keine Branches. git pull --rebase origin feature/xyz bzw. git push origin feature/xyz wird ausgeführt.
Kann ich eine andere Remote als origin verwenden?
Ja, per Config oder CLI-Option (indirekt über Config oder Umgebungsvariable):
# Per Umgebungsvariable
SYNC_REMOTE=upstream git-sync-all
# Per Config
echo 'SYNC_REMOTE="upstream"' >> ~/.config/git-sync-all/config.conf
Was ist das Repository-Inventar?
Eine YAML-Datei (repos.yml), die definiert, welche Repos auf einer Maschine vorhanden sein sollen. Mit --verify wird geprüft, ob alle aufgelisteten Repos tatsächlich existieren. Nützlich um sicherzustellen, dass auf einem neuen Rechner oder nach einer Neuinstallation alle Projekte geclont sind.
# Inventar erstellen
git-sync-all --init-inventory
# Alle Repos prüfen
git-sync-all --verify
# Nur bestimmte Gruppe prüfen
git-sync-all --verify --group work
# Standard-Gruppe per Config setzen (statt "all")
# In config.conf:
# SYNC_VERIFY_GROUP="public,private"
Seit v1.3.0 erkennt --verify auch Repos auf der Festplatte, die nicht im Inventar stehen, und bietet an, diese zu entfernen.
Seit v1.4.0 unterstützt repos.yml optionale Clone-URLs für externe Repos (- name: https://url). Bei fehlenden Repos werden konkrete Clone-Befehle angezeigt.
Wie kann ich offene GitHub Issues meiner Repos sehen?
Mit --issues werden offene Issues aller Repos im Inventar abgefragt. Mit -v werden zusätzlich Issue-Nummern und Titel angezeigt. Voraussetzung: gh CLI installiert und authentifiziert.
# Alle Inventar-Repos
git-sync-all --issues
# Bestimmte Gruppe
git-sync-all --issues --group work
# Mit Details
git-sync-all --issues --group work -v
Lizenziert unter der MIT-Lizenz.
| Ressource | Link |
|---|---|
| GitHub Repository | https://github.com/markus-michalski/git-sync-all |
| Releases | https://github.com/markus-michalski/git-sync-all/releases |
| Issues / Bug-Reports | https://github.com/markus-michalski/git-sync-all/issues |
| Changelog | https://github.com/markus-michalski/git-sync-all/blob/main/CHANGELOG.md |