Konfigurationsdateien im Home Directory mit Git zwischen macOS und Kubuntu Linux synchronisieren
Hat man einen neuen Laptop oder PC, beginnt das zeitraubende und wenig anspruchsvolle einrichten der Arbeitsumgebung. Es müssen Apps und Tools installiert werden und Konfigurationsdateien erstellt und angepasst werden.
Aber stopp 🛑, es gibt eine einfache und effiziente Möglichkeit die wichtigen Konfigurationsdateien über ein Git Repository für MacOS und Linux zentral zu verwalten und bei Bedarf schnell auf den neuen Client zu holen.
Da die meisten Apps für Linux und MacOS verfügbar sind und auch die Ordnerstruktur gleich aufgebaut werden kann, eignet sich Git für diese Aufgabe besonders gut.
Das Ziel
Git Prozess
-
Es soll ein Git Repository mit Ordnern, Unterordnern und Konfigurationsdateien auf mehreren Clients, MacOS und Linux, synchronisiert werden.
-
Der Aufwand für das Anpassen der Dateien auf jedem neuen Client soll entfallen. Dafür soll einfach das Git Repository auf den Client geclont werden.
-
Der Abonnements im RSS-Reader
Newsboatsollen über das Git Repository verwaltet und damit auf allen Clients auf dem gleichen Stand gehalten werden. (👉 The Newsboat RSS Feedreader - RSS-Reader für die CLI, 👉 YouTube-Channels in Newsboat abonnieren - So geht’s mit RSS-Feeds, 👉 iTerm2-Profile für Newsboat mit Shortcut starten)
Die Dateien enthalten keine persönlichen und sensiblen Daten oder diese Daten sind mithilfe von GnuPG verschlüsselt, z.B. für den Zugriff auf Wallabag. (👉 Wallabag - Installation mit Docker Compose, 👉 Newsboat kann RSS Feed von Wallabag abrufen, 👉 Read it Later - Sende Artikel aus Newsboat direkt an Wallabag)
Voraussetzung
Die Betriebssysteme, sei ein MacOS oder ein Linux, verwenden die gleiche Ordnerstruktur innerhalb des jeweiligen Home-Verzeichnisses Die Ordner und Dateien sind dort gleich benannt.
Der Pfad des Home-Verzeichnisses unterscheidet sich bei den Betriebssystemen.
| Linux | Apple |
|---|---|
/home/<benutzer |
/Users/<benutzer |
Im Home-Verzeichnis sind die Ordnernamen gleich benannt.
| Linux | Apple |
|---|---|
~/Downloads |
~/Downloads |
~/Pictures |
~/Pictures |
~/.ssh |
~/.ssh |
~/.config |
~/.config |
~/.ranger |
~/.ranger |
Eigene Skripte und Konfigurationsdateien
Für meine Skripte verwende ich nach Möglichkeit absolute Pfade. Damit können die Skripte auf den beiden Betriebssystemen verwendet werden udn aus dem namentlich gleichen Ordner heraus ausgeführt werden.
✅ In Skripten. z.B. watermark.sh, lässt sich das ebenfalls so umsetzen. (👉 Bilder - Wasserzeichen einfügen und Metadaten entfernen)
| Linux | Apple |
|---|---|
| WATERMARK="$HOME/Arbeitsordner/_screenshots/bilder-mit-wasserzeichen" | WATERMARK="$HOME/Arbeitsordner/_screenshots/bilder-mit-wasserzeichen" |
.zshrc und .bashrc
✅ In .zshrc können Aliase definiert werden, die auf beiden Systemen funktionieren. Das Gleiche gilt auch für .bashrc.
| Linux | Apple |
|---|---|
| alias nnm='XDG_CONFIG_HOME=~/.newsboat-music XDG_DATA_HOME=.newsboat-music newsboat' | alias nnm='XDG_CONFIG_HOME=~/.newsboat-music XDG_DATA_HOME=.newsboat-music newsboat' |
✅ Programme, die in der CLI laufen, wie z.B. Ranger, htop, bpytop, etc., können ebenfalls auf beiden Betriebssystemen über den gleichen Alias gestartet werden. (👉 Ranger - Der bessere File Manager, 👉 weitere Ranger-Beiträge)
| Linux | Apple |
|---|---|
| alias rr='ranger' | alias rr='ranger' |
| alias ll='ls -lah' | alias ll='ls -lah' |
| alias lt='ls -lhtF' | alias lt='ls -lhtF' |
Starten von grafischen Programmen
🛑 Grafische Programme, wie z.B. Firefox, Brave, etc., werden bei den beiden Betriebssystemen anders gestartet. Deshalb können zwar die gleichen Aliase in .zshrc angelegt werden, der Startbefehl für die Apps unterscheiden sich jedoch.
| Linux | Apple |
|---|---|
| alias ff='open -a Firefox' | alias ff='setsid firefox >/dev/null 2>&1' |
| alias bb='setsid brave >/dev/null 2>&1' | alias bb='open -a Brave Browser' |
Gib mir gerne einen Kaffee ☕ aus 😀
Gib mir gerne einen Kaffee ☕ aus !
Wenn dir meine Beiträge gefallen und geholfen haben, dann kannst du mir gerne einen Kaffee ☕️ ausgeben.
Hardware, Betriebssysteme und Software
In meinem Use Case verwende ich die folgende Hardware und Betriebssysteme
- ein MacBook Air mit Tahoe 26.2
- ein Laptop mit Kubuntu 25.10 - Plasma 6
- ein Raspberry Pi mit dem aktuellen Raspberry Pi OS
Als Git Client wird jeweils auf die CLI und auf grafische Clients verwendet:
- MacOS → Fork https://git-fork.com/
- Linux → Git Cola https://git-cola.github.io/
Git-Server
Das Git Repository wird über einen eigenen Git-Server auf einer Synology NAS verwaltet. Dafür wird Gitea verwendet, dass mithilfe von Docker Compose installiert und verwaltet wird.
Gitea verwende ich bereits seit Jahren. Eine Migration zu Forgejo steht schon seit langer Zeit auf meiner To-Do-Liste.
Es muss keine Synology für eine Docker-Umgebung verwendet werden. Das kostenlose NAS 👉 openmediavault eignet sich ebenfalls für diesen Zweck.
Das Vorgehen
Das Home-Verzeichnis enthält sehr viele Ordner und Dateien mit sehr sensiblen Informationen. Zudem ist das gesamte Verzeichnis sehr groß.
Es werden deshalb ALLE Ordner und Dateien zu Beginn vom Git Repository ausgeschlossen. Anschließend wird ganz selektiv festgelegt, welche Ordner und Dateien in das Repository aufgenommen werden sollen.
Die gesamten Einstellungen werden in die .gitignore-Datei eingetragen.
Das Ausschließen (= ignore) wird in der ersten Zeile festgelegt:
# Ignore everything by default
*
In den nächsten Zeilen werden die Ordner und Dateien eingetragen, die zum Git Repository hinzugefügt werden sollen.
Inhalt von /home/<benutzer> bzw. /Users/<benutzer> auslesen
Für das Erstellen der .gitignore ist es hilfreich die Ordner- und Dateinamen von /home/<benutzer> /home/<benutzer> bzw. /Users/<benutzer> in eine Text-Datei schreiben zu lassen. Daraus können die Einträge per Copy-and-Paste entnommen werden. Vertipper werden damit so gut wie ausgeschlossen.
cd /home/<benutzer>
gls -ahf > tree.txt
Es wird eine neue Datei in /home/<benutzer> mit dem Namen tree.txt angelegt. Diese Datei kann mit jedem Editor geöffnet und bearbeitet werden.
.gitignore Vorbereiten
Die Datei tree.txt ist mit einem Texteditor zu öffnen. Es sind alle Ordner- und Dateinamen zu löschen, die nicht im Git Repository enthalten sein sollen.
Meine Datei enthält nur noch die folgenden Zeilen:
.config/
.gitconfig
.newsboat/
.newsboat-finance/
.newsboat-klima-energie/
.newsboat-music/
.newsboat-nextcloud/
.newsboat-politik-wirtschaft/
.ssh/
.tmux.conf
Anschließend wird am Anfang einer jeden Zeile ein ! gesetzt. Damit wird dieser Ordner bzw. Datei in das Git Repository aufgenommen. (= unignore)
Zudem muss jede Zeile mit einem Unterordnernamen erneut eingefügt werden mit ** am Ende. Das gewährleistet, dass Git einen Zugriff auf den Inhalt des Ordners bekommt.
# Unignore
!.config/
!.config/ranger/
!.config/ranger/**
!.config/scripts/
!.config/scripts/**
!.gitconfig
!/.newsboat/
!/.newsboat/**
!/.newsboat-finance/
!/.newsboat-finance/**
!.newsboat-klima-energie/
!.newsboat-klima-energie/**
!.newsboat-music/
!.newsboat-music/**
!.newsboat-nextcloud/
!.newsboat-nextcloud/**
!.newsboat-politik-wirtschaft/
!.newsboat-politik-wirtschaft/**
!.ssh/
!.ssh/**
!.tmux.conf
!.zshrc-apple
!.zshrc-linux
Unterordner in .config
Es sollen zwei Unterordner aus dem Verzeichnis ~/.config in das Git Repository übernommen werden. Mit der aktuellen .gitignore-Konfiguration werden diese Unterordner aber ignoriert. Sie müssen explizit um Git Repository hinzugefügt (= unignore) werden.
| .config/
|
|- ranger
|
|- scripts
Dazu ist es notwendig erst den Ordner .config in das Repository aufzunehmen und dann die Unterordner mit einzubeziehen.
# Unignore
!.config/
!.config/ranger
!.config/scripts
.bashrc und .zshrc
Die beiden Dateien .bashrc und .zshrc sind auf meinen Clients ein ganz wichtiger Bestandteil meiner Arbeitsumgebung. Dort sind Aliase definiert, die helfen Programme von der CLI zu starten oder Befehle auszuführen, die ich regelmäßig benötige. (👉 zsh - Die Standard-Shell von macOS aufbohren, 👉 zsh und Aliase - Tastenkürzel zum Starten von Programmen nutzen, 👉 Meine Software - Eine Übersicht - Teil 3)
.bashrc oder .zshrc
Linux und MacOS unterscheiden sich in einigen grundlegenden Funktionen. Das wird besonders beim Starten von Apps von der CLI ersichtlich.
Es ist deshalb eine Strategie festzulegen, wie mit diesen Dateien umgegangen werden soll.
Meine Strategie:
- Es wird bei MacOS und Linux jeweils eine eigen
.zshrcverwendet. - Es wird nach jeder Änderung auf dem Client eine Kopie der Datei erstellt und mit dem Namen
.zshrc-linuxoder.zshrc-appleim Home-Verzeichnis abgespeichert. - Die Originaldatei
.zshrcwird nicht im Repo verwaltet, sondern nur die Dateien.zshrc-linuxund.zshrc-apple - Die beiden Dateien werden damit mit dem Git Repository auf jeden Client übertragen und muss dort dann als Kopie mit dem Namen
.zshrcangelegt werden.
Gib mir gerne einen Kaffee ☕ aus 😀
Gib mir gerne einen Kaffee ☕ aus !
Wenn dir meine Beiträge gefallen und geholfen haben, dann kannst du mir gerne einen Kaffee ☕️ ausgeben.
Die fertige .gitignore
Die fertige .gitignore enthält alle wichtigen Ordner und Dateien. Ebenfalls habe ich die .gitignore mit aufgenommen.
# Ignore everything by default
*
# Unignore
!.config/
!.config/ranger/
!.config/ranger/**
!.config/scripts/
!.config/scripts/**
!.gitconfig
!.gitignore
!.gitignore_global
!/.newsboat/
!/.newsboat/**
!/.newsboat-finance/
!/.newsboat-finance/**
!.newsboat-klima-energie/
!.newsboat-klima-energie/**
!.newsboat-music/
!.newsboat-music/**
!.newsboat-nextcloud/
!.newsboat-nextcloud/**
!.newsboat-politik-wirtschaft/
!.newsboat-politik-wirtschaft/**
!.ssh/
!.ssh/**
!README.md
!.tmux.conf
!.zshrc-apple
!.zshrc-linux
##################
# Must be placed at the end of the .gitignore
##################
# Ignore macOS junk everywhere
.DS_Store
._.DS_Store
**/.DS_Store
**/._.DS_Store
# SSH
authorized_keys
config.save
known_hosts
known_hosts.old
# Newsboat Cache
cache.db
cache.db.lock
history.cmdline
history.search
.newsboat/response_body.txt
.newsboat*/newsboat/response_body.txt
# Ranger
__pycache__
__init__.py
ranger_devicons
*.bak
*.*-bak
MacOS hat die Angewohnheit in jeden Ordner die Datei .DS_Store zu legen. Die Datei wird im Git Repository aber nicht benötigt. Deshalb kann sie einfach weggelassen werden.
Damit das funktioniert, muss der ignore-Absatz am Ende der .gitignore eingefügt werden.
Neben der .DS_Store werden noch einige Dateien ignoriert, die nicht im Git Repository verwaltet werden sollen.
Damit ist die .gitignore fertig und kann in das Verzeichnis /home/<benutzer> kopiert werden.
DS_Store über eine globale Regel immer ignorieren
.DS_Store kann über eine globale Datei immer von Git Repositories ausgeschlossen werden. Der Eintrag in jeder .gitignore wird damit überflüssig.
cd
touch .gitignore_global
Der Inhalt der Datei kann auch mehr Dateien umfassen.
# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so
# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
# Logs and databases #
######################
*.log
*.sql
*.sqlite
# OS generated files #
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
Diese Datei muss in der globalen .gitconfig hinzugefügt werden.
git config --global core.excludesfile ~/.gitignore_global
Für dieses Vorhaben funktioniert die globale Datei jedoch nicht. Git arbeitet der Reihe nach die Dateien ab:
/.gitignore_global/.gitignore
Da in der .gitignore wieder Ordern expliziert mit allen Dateien (**) hinzugefügt werden, beinhaltes das auch die DS_Store-Dateien. Der Ausschluss (= ignore) erfolgt dann erneut explizit am Ende der /.gitignore.
Die Krux mit .ssh
Das Verzeichnis .ssh inkl. dessen Inhalt ist mit Zugriffsrechte geschützt. Git kann ggf. nicht schreibend auf das Verzeichnis bzw. die Dateien zugreifen und bricht den Synchronisationsprozess ab.
Die wichtige Datei im Verzeichnis .ssh ist die config-Datei in der die Aliase für die SSh-Verbindungen verwaltet werden. Diese kann im Normalfall mit den Zugriffsrechten des eigenen Benutzers bearbeitet werden und somit auch über das Git-Repository verwaltet werden.
In diesem Fall ist eine kleine Anpassung in der .gitignore notwendig.
!.ssh/
!.ssh/**
!.ssh/
!.ssh/config
Der SSH-Abschnitt am Ende der Datei kann ebenfalls entfernt werden. Es wird nur noch die Datei .ssh/config im Git Repository verwaltet.
Git Repository anlegen und auf Git-Server übertragen
Das Git Repository kann nun angelegt und auf den Git-Server übertragen werden.
Gitea
Anlegen einer eigenen Organisation für die Repositories
Repository erstellen
Repository wurde erstellt
Auf dem eigenen Client
Das Git Repository wird auf dem MacBook Air mit Tahoe 26.2 erstellt und auf den Server übertragen.
Dazu wechselt man in der CLI in das Verzeichnis /home/<benutzer>.
# Aktuellen Pfad in CLI anzeigen
pwd
# Bei MacOS
/Users/<benutzer>
# Bei Linux
/home/<benutzer>
❯ git init
Hinweis: Using 'master' as the name for the initial branch. This default branch name
Hinweis: will change to "main" in Git 3.0. To configure the initial branch name
Hinweis: to use in all of your new repositories, which will suppress this warning,
Hinweis: call:
Hinweis:
Hinweis: git config --global init.defaultBranch <name>
Hinweis:
Hinweis: Names commonly chosen instead of 'master' are 'main', 'trunk' and
Hinweis: 'development'. The just-created branch can be renamed via this command:
Hinweis:
Hinweis: git branch -m <name>
Hinweis:
Hinweis: Disable this message with "git config set advice.defaultBranchName false"
Leeres Git Repository in /Users/<benutzer>/.git/ initialisiert
/Users/<benutzer>/.git bzw. /home/<benutzer>/.git
Es wird der Ordner /Users/<benutzer>/.git im Home-Verzeichnis angelegt. Dort finden sich alle Ordner und Dateien für das Git Repository.
.
├── config
├── description
├── HEAD
├── hooks
│ ├── applypatch-msg.sample
│ ├── commit-msg.sample
│ ├── fsmonitor-watchman.sample
│ ├── post-update.sample
│ ├── pre-applypatch.sample
│ ├── pre-commit.sample
│ ├── pre-merge-commit.sample
│ ├── pre-push.sample
│ ├── pre-rebase.sample
│ ├── pre-receive.sample
│ ├── prepare-commit-msg.sample
│ ├── push-to-checkout.sample
│ ├── sendemail-validate.sample
│ └── update.sample
├── info
│ └── exclude
├── objects
│ ├── info
│ └── pack
└── refs
In der config-Datei können Einstellungen zum neuen Git Repository vorgenommen werden. Ein grafischer Git Client holt aus dieser Dateien die Informationen und schreibt die Einstellungen dort zurück.
Der Branch main wird erstellt.
git checkout -b main
Zu neuem Branch 'main' gewechselt
Alle Ordner und Dateien, die in das Git Repository aufgenommen werden, können angezeigt werden mit git status.
Ein grafischer Git Client, wie Fork https://git-fork.com/, gibt einen besseren Überblick. (👉 git-flow mit Fork - a fast and friendly git client for Mac and Windows)
git status
Die Ordner und Dateien können nun zum Git Repository hinzugefügt und mit einer Beschreibung versehend werden.
git add *
git commit -m "first commit"
Nun kann alles zum Git-Server gesendet werden:
git remote add origin ssh://git@git.example.com:22/clients/linux-macos.git
git push -u origin main
Ich verwende dafür einen 👉 YubiKey, der zudem alle Commits signiert und anschließend die Authentifizierung am Git Server vornimmt. Für das Ganze muss der Hardwaretoken am Client angeschlossen und entsperrt sein.
Signierter Commit in Gitea
In Gitea sieht das Repository ohne Readme irgendwie unfertig aus. Deshalb habe ich im nächsten Commit noch eine README.md mit übertragen. Dazu musste die Zeile !README.md in der .gitignore hinzugefügt werden.
...
!.ssh/**
!README.md
!.tmux.conf
...
README.md in Gitea
Auf dem Kubuntu Laptop
Auf meinem Kubuntu Laptop wird der YubiKey verwendet, um das Git Repository auf den Client zu klonen, die Änderungen zu signieren und wieder auf den Git Sever zu laden.
Dafür sind ein paar Kleinigkeiten einzustellen, damit dieser Workflow funktioniert.
Git vorbereiten
Auf dem Kubuntu Laptop ist Git und der öffentliche GPG-Schlüssel miteinander zu verbinden, damit die Commits ordentlich Signiert werden können.
In der .bashrc bzw. .zshrc ist die Zeile einzutragen.
export GPG_TTY=$(tty)
Der öffentliche GPG-Schlüssel ist in den Schlüsselbund zu importieren.
Das KDE-Tool KPgp ist ein grafisches Frontend und erleichtert den Umgang mit GPG-Schlüsseln. Es lässt sich einfach über den Paketmanager installieren.
sudo apt install kgpg
Nach der Installation kann der öffentliche Schlüssel, die asc-Datei, einfach per Drag-and-Drop in das Programm importiert werden.
In den Schlüsseleigenschaften ist das Vertrauenslevel auf Unbedingt zu setzen.
Getestet wird mit dem Befehl
echo text | gpg --clearsign
Als Ausgabe erhält man die PGP Signatur.
Ausgabe des Tests in CLI
In die Datei .git/config ist einzutragen, welcher GPG-Schlüssel für das Signieren verwendet werden soll.
git config user.signingkey <Schlüssel-Kennung>
In der Datei .git/config wird eine neue Zeile hinzugefügt. Der Abschnitt [user] kann wie folgt aussehen.
[user]
name = <Benutzername>
email = <benutzername@example.com>
signingkey = <Schlüssel-Kennung>
Die kann das Signierverhalten für Git auch global, in der zentralen .gitconfig vorgegeben werden. Nach einem Sync wird diese Datei in das Repository übertragen und kann anschließend auf alle Clients übertragen werden.
Es wird die Zeile in der Datei hinzugefügt:
git config --global user.signingkey <Schlüssel-Kennung>
Schlüssel-Kennung herausfinden
Die Schlüssel-Kennung kann über KGpg abgefragt werden:
Schlüsseleigenschafte --> Schlüsselkennung
Git Repository klonen
Auf dem Kubuntu-Laptop ist ein kleiner Workaround notwendig. Wird lediglich ein git clone im Home-Verzeichnis ausgeführt, erstellt Git einen den Ordner /home/<benutzer>/linux-macos und kopiert in diesen alle Dateien.
Das Git Repository soll aber direkt im Home-Verzeichnis angelegt werden. Dazu ist ein kleiner Umweg notwendig.
Das Git Repository wird geklont und es wird der Ordner /home/<benutzer>/linux-macos angelegt, in dem alle Dateien enthalten sind.
cd
git clone ssh://git@git.example.com:22/clients/linux-macos.git
.git und .gitignore in Home-Verzeichnis kopieren
Es ist das gesamte Verzeichnis .git in /home/<benutzer>/ zu kopieren, entweder per Konsole oder mit Dolphin.
cd linux-macos
cp -r .git /home/<benutzer>
cp -r .gitignore /home/<benutzer>
Anschließend ist der neue Pfad im lokalen Git Repository korrekt zu setzen.
cd
git checkout .
Der Ordner /home/<benutzer>/linux-macos kann nun gelöscht werden.
rm -r /home/<benutzer>/linux-macos
Git Repository synchronisieren
Das Git Repository ist nun am richtigen Ort und kann über den Git Server synchronisiert werden.
git status
Git Commit in Git Cola
Neuer Commit in Gitea (Git Server)
Troubleshooting
git code 128 gpg failed to sign the data
Das Betriebssystem und Git sind vorzubereiten 👉 Git vorbereiten.
Möchte man das Signieren global anschalten, kann in .gitconfig die Zeile ergänzt werden:
[commit]
gpgsign = true
[commit]
gpgsign = false
Gib mir gerne einen Kaffee ☕ aus 😀
Gib mir gerne einen Kaffee ☕ aus !
Wenn dir meine Beiträge gefallen und geholfen haben, dann kannst du mir gerne einen Kaffee ☕️ ausgeben.
Follow Me
Source
Photo by Yancy Min on Unsplash










