Zum Inhalt

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

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.

Donation via PayPalDonation via LiberaPay

Donation via Bitcoin
Bitcoin Address:

bc1qfuz93hw2fhdvfuxf6mlxlk8zdadvnktppkzqzj


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:


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 .zshrc verwendet.
  • Es wird nach jeder Änderung auf dem Client eine Kopie der Datei erstellt und mit dem Namen .zshrc-linux oder .zshrc-apple im Home-Verzeichnis abgespeichert.
  • Die Originaldatei .zshrc wird nicht im Repo verwaltet, sondern nur die Dateien .zshrc-linux und .zshrc-apple
  • Die beiden Dateien werden damit mit dem Git Repository auf jeden Client übertragen und muss dort dann als Kopie mit dem Namen .zshrc angelegt 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.

Donation via PayPalDonation via LiberaPay

Donation via Bitcoin
Bitcoin Address:

bc1qfuz93hw2fhdvfuxf6mlxlk8zdadvnktppkzqzj


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:

  1. /.gitignore_global
  2. /.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.

Alter Eintrag
!.ssh/
!.ssh/**
Neuer Eintrag
!.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:

Signieren ANschalten 🟩
[commit]
    gpgsign = true
Signieren ABschalten 🟥
[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.

Donation via PayPalDonation via LiberaPay

Donation via Bitcoin
Bitcoin Address:

bc1qfuz93hw2fhdvfuxf6mlxlk8zdadvnktppkzqzj

Source

Photo by Yancy Min on Unsplash