GNU Stow: Automatisiertes Symlink-Management für Dotfiles
Jeder, der schon einmal versucht hat, Dotfiles zwischen mehreren Systemen zu synchronisieren, kennt das Problem: Dutzende ln -sf-Befehle, die man bei jeder Neuinstallation von Hand ausführen muss. GNU Stow löst dieses Problem elegant und automatisiert das Symlink-Management mit einem einzigen Befehl.
Dieser Artikel baut auf dem Dotfiles-Grundlagen-Post auf. Falls du noch nicht mit Dotfiles und Symlinks vertraut bist, lies dort zuerst nach.
Was ist GNU Stow?
GNU Stow ist ein Symlink-Farm-Manager - ein Tool, das automatisch symbolische Links von einem Quellverzeichnis in ein Zielverzeichnis erstellt. Ursprünglich wurde es für die Verwaltung von Software in /usr/local entwickelt, hat sich aber als perfektes Werkzeug für Dotfiles-Management etabliert.
Warum Stow statt manueller Symlinks?
| Manuell | Mit GNU Stow |
|---|---|
ln -sf ~/dotfiles/zsh/.zshrc ~/.zshrc |
stow zsh |
ln -sf ~/dotfiles/git/.gitconfig ~/.gitconfig |
stow git |
ln -sf ~/dotfiles/tmux/.tmux.conf ~/.tmux.conf |
stow tmux |
| 20+ Befehle für ein komplettes Setup | Ein Befehl: stow */ |
Vorteile von Stow:
- Ein Befehl statt vieler
ln -sf-Aufrufe - Automatische Erkennung der richtigen Pfade
- Sauberes Entfernen von Symlinks mit
stow -D - Dry-Run-Modus zum Testen
- Konflikt-Erkennung verhindert Datenverlust
- Keine Dependencies - reines Perl, auf fast jedem System verfügbar
Installation
GNU Stow ist in den Paketquellen aller gängigen Distributionen enthalten:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Debian/Ubuntu
sudo apt install stow
# Fedora
sudo dnf install stow
# Arch Linux
sudo pacman -S stow
# openSUSE
sudo zypper install stow
# macOS (Homebrew)
brew install stow
Version prüfen:
1
2
stow --version
# stow (GNU Stow) version 2.3.1
Das Stow-Grundkonzept
Stow arbeitet mit drei zentralen Konzepten:
Die drei Kernkonzepte von GNU Stow
1. Stow Directory
Das Stow Directory ist der Ordner, in dem deine Pakete liegen. Standardmäßig ist das das aktuelle Verzeichnis.
1
2
# Explizit angeben mit -d oder --dir
stow -d ~/dotfiles zsh
2. Package
Ein Package ist ein Unterordner im Stow Directory. Jedes Paket enthält die Dateien und Ordner, die verlinkt werden sollen - in der exakt gleichen Struktur wie im Zielverzeichnis.
3. Target Directory
Das Target Directory ist das Ziel für die Symlinks. Standardmäßig ist das das Elternverzeichnis des Stow Directory.
1
2
# Explizit angeben mit -t oder --target
stow -t ~ zsh
Wichtig: Wenn dein Dotfiles-Ordner in
~/dotfiles/liegt, ist das Target automatisch~(Home). Das ist genau das, was wir für Dotfiles wollen!
Die richtige Verzeichnisstruktur
Der Schlüssel zu erfolgreichem Stow-Einsatz ist die korrekte Verzeichnisstruktur. Die Paketstruktur muss die Zielstruktur exakt spiegeln.
Die Paketstruktur spiegelt die Zielstruktur
Einfache Dotfiles im Home-Verzeichnis
Für Dateien, die direkt in ~ landen sollen:
1
2
3
4
5
6
7
8
~/dotfiles/
├── zsh/
│ ├── .zshrc # wird zu ~/.zshrc
│ └── .zprofile # wird zu ~/.zprofile
├── git/
│ └── .gitconfig # wird zu ~/.gitconfig
└── tmux/
└── .tmux.conf # wird zu ~/.tmux.conf
Verschachtelte Strukturen (.config/)
Für Dateien in ~/.config/ musst du die komplette Pfadstruktur im Paket abbilden:
1
2
3
4
5
6
7
~/dotfiles/
└── nvim/
└── .config/ # Dieser Pfad wird gespiegelt!
└── nvim/
├── init.lua
└── lua/
└── plugins.lua
Nach stow nvim existiert:
~/.config/nvim/→ Symlink zudotfiles/nvim/.config/nvim/
Häufiger Fehler: Die
.config/-Ebene vergessen! Ohne sie würde Stow versuchen,nvim/direkt in~anzulegen.
Komplettes Beispiel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
~/dotfiles/
├── zsh/
│ ├── .zshrc
│ └── .zprofile
├── git/
│ └── .gitconfig
├── tmux/
│ └── .tmux.conf
├── nvim/
│ └── .config/
│ └── nvim/
│ ├── init.lua
│ └── lua/
├── alacritty/
│ └── .config/
│ └── alacritty/
│ └── alacritty.toml
└── ssh/
└── .ssh/
└── config
Basis-Kommandos
Symlinks erstellen (Stow)
1
2
3
4
5
6
7
8
9
10
cd ~/dotfiles
# Einzelnes Paket
stow zsh
# Mehrere Pakete
stow zsh git tmux
# Alle Pakete (Globbing)
stow */
Symlinks entfernen (Unstow)
1
2
3
4
5
# Mit -D oder --delete
stow -D zsh
# Mehrere Pakete
stow -D zsh git tmux
Restow (Delete + Stow)
Nützlich nach Änderungen an der Paketstruktur:
1
2
# Mit -R oder --restow
stow -R zsh
Dry-Run (Simulation)
Zeigt, was passieren würde, ohne Änderungen vorzunehmen:
1
2
3
# Mit -n oder --no
stow -n zsh
# LINK: .zshrc => dotfiles/zsh/.zshrc
Verbose Output
Für mehr Details:
1
2
3
4
5
6
# Mit -v (mehrfach für mehr Details: -vv, -vvv)
stow -v zsh
# LINK: .zshrc => dotfiles/zsh/.zshrc
stow -vv zsh
# Detaillierter Output mit Pfadauflösung
Kommando-Übersicht
| Kommando | Kurzform | Funktion |
|---|---|---|
stow <pkg> |
- | Symlinks erstellen |
stow --delete <pkg> |
-D |
Symlinks löschen |
stow --restow <pkg> |
-R |
Delete + Stow |
stow --no <pkg> |
-n |
Dry-Run (nur anzeigen) |
stow --verbose <pkg> |
-v |
Verbose Output |
stow --dir=DIR |
-d DIR |
Stow Directory angeben |
stow --target=DIR |
-t DIR |
Target Directory angeben |
Praxis-Beispiele
Beispiel 1: Einfache Dotfiles
Ein minimales Setup für zsh, git und tmux:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Struktur erstellen
mkdir -p ~/dotfiles/{zsh,git,tmux}
# Bestehende Configs kopieren
cp ~/.zshrc ~/dotfiles/zsh/
cp ~/.gitconfig ~/dotfiles/git/
cp ~/.tmux.conf ~/dotfiles/tmux/
# Alte Dateien entfernen (Stow braucht freie Ziele)
rm ~/.zshrc ~/.gitconfig ~/.tmux.conf
# Symlinks erstellen
cd ~/dotfiles
stow zsh git tmux
# Prüfen
ls -la ~ | grep -E "zshrc|gitconfig|tmux"
# lrwxrwxrwx .gitconfig -> dotfiles/git/.gitconfig
# lrwxrwxrwx .tmux.conf -> dotfiles/tmux/.tmux.conf
# lrwxrwxrwx .zshrc -> dotfiles/zsh/.zshrc
Beispiel 2: Neovim mit .config/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Struktur mit verschachteltem .config
mkdir -p ~/dotfiles/nvim/.config/nvim
# Bestehende Config verschieben
mv ~/.config/nvim/* ~/dotfiles/nvim/.config/nvim/
# Altes Verzeichnis entfernen
rmdir ~/.config/nvim
# Stow ausführen
cd ~/dotfiles
stow nvim
# Prüfen
ls -la ~/.config/
# lrwxrwxrwx nvim -> ../dotfiles/nvim/.config/nvim
Beispiel 3: Alle Pakete auf einmal
1
2
3
4
5
6
7
8
9
10
11
12
13
cd ~/dotfiles
# Dry-Run für alle Pakete
stow -n */
# Wenn alles gut aussieht: ausführen
stow */
# Output:
# LINK: .zshrc => dotfiles/zsh/.zshrc
# LINK: .gitconfig => dotfiles/git/.gitconfig
# LINK: .tmux.conf => dotfiles/tmux/.tmux.conf
# LINK: .config/nvim => ../dotfiles/nvim/.config/nvim
Beispiel 4: Setup von Grund auf
Komplettes Dotfiles-Repository für ein neues System:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 1. Repository klonen
git clone [email protected]:user/dotfiles.git ~/dotfiles
# 2. Ins Verzeichnis wechseln
cd ~/dotfiles
# 3. Alle Pakete stow'en (Dry-Run zuerst)
stow -n */
# 4. Bei Konflikten: existierende Dateien sichern
# (siehe Troubleshooting)
# 5. Stow ausführen
stow */
# 6. Shell neu laden
exec zsh
Fortgeschrittene Features
–target: Alternatives Zielverzeichnis
Standardmäßig ist das Target das Elternverzeichnis. Mit -t kannst du ein anderes Ziel angeben:
1
2
3
4
5
# Symlinks in /etc erstellen (benötigt sudo)
sudo stow -t /etc myetc
# Von überall aus arbeiten
stow -d ~/dotfiles -t ~ zsh
–dir: Alternatives Stow Directory
1
2
3
4
5
# Stow Directory explizit angeben
stow -d /path/to/dotfiles zsh
# Kombination mit --target
stow -d ~/dotfiles -t ~ zsh git tmux
–ignore: Dateien ausschließen
Mit --ignore kannst du Dateien vom Stowing ausschließen:
1
2
3
4
5
# README und LICENSE ignorieren
stow --ignore='README.*' --ignore='LICENSE' zsh
# Backup-Dateien ignorieren
stow --ignore='.*\.bak' --ignore='.*~' zsh
.stow-local-ignore: Permanente Ignore-Regeln
Erstelle eine .stow-local-ignore-Datei im Paket für permanente Ausschlüsse:
1
2
3
4
5
# ~/dotfiles/zsh/.stow-local-ignore
README.md
LICENSE
\.git
.*\.bak
Die Datei verwendet Perl-Regex-Syntax, keine Glob-Patterns!
–adopt: Existierende Dateien übernehmen
--adopt ist mächtig aber gefährlich: Es verschiebt existierende Dateien ins Paket und erstellt dann Symlinks.
1
2
# Vorsicht: Überschreibt Dateien im Paket!
stow --adopt zsh
Workflow mit –adopt:
1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. Dry-Run
stow -n --adopt zsh
# LINK: .zshrc => dotfiles/zsh/.zshrc (ADOPTED)
# 2. Ausführen
stow --adopt zsh
# 3. Änderungen prüfen
cd ~/dotfiles
git diff
# 4. Bei Bedarf zurücksetzen
git checkout -- zsh/.zshrc
Warnung:
--adoptüberschreibt Dateien im Paket ohne Nachfrage! Immer vorhergit statusprüfen und ggf. committen.
–no-folding: Immer Datei-Symlinks
Standardmäßig erstellt Stow Verzeichnis-Symlinks wenn möglich (genannt “Tree Folding”). Mit --no-folding werden stattdessen einzelne Datei-Symlinks erstellt:
1
2
3
4
5
6
7
8
9
# Standard (Tree Folding)
stow nvim
# ~/.config/nvim -> ../dotfiles/nvim/.config/nvim (ein Symlink)
# Mit --no-folding
stow --no-folding nvim
# ~/.config/nvim/init.lua -> ../../dotfiles/nvim/.config/nvim/init.lua
# ~/.config/nvim/lua/plugins.lua -> ...
# (mehrere Symlinks)
Wann –no-folding verwenden?
- Wenn du manche Dateien in einem Verzeichnis nicht verlinken willst
- Bei Konflikten mit anderen Paketen
- Wenn andere Programme Dateien im gleichen Verzeichnis erstellen sollen
–override und –defer: Konflikt-Handling
Diese Optionen steuern, wie Stow mit Konflikten umgeht:
1
2
3
4
5
# --override: Bestimmte Pfade dürfen überschrieben werden
stow --override='\.config/nvim/.*' nvim
# --defer: Bestimmte Pfade werden übersprungen wenn belegt
stow --defer='\.bashrc' bash
Anwendungsfall: Wenn mehrere Pakete die gleiche Datei haben könnten:
1
2
3
4
5
# base-Paket hat .bashrc
stow base
# bash-extras-Paket hätte auch .bashrc, aber defer
stow --defer='\.bashrc' bash-extras
Troubleshooting
Problem: “existing target is not owned by stow”
Ursache: Eine reguläre Datei existiert bereits am Zielort.
1
2
3
4
$ stow zsh
WARNING! stowing zsh would cause conflicts:
* existing target is neither a link nor a directory: .zshrc
All operations aborted.
Lösungen:
1
2
3
4
5
6
7
8
9
# Option 1: Datei manuell sichern und löschen
mv ~/.zshrc ~/.zshrc.backup
stow zsh
# Option 2: --adopt verwenden (überschreibt Paket-Datei!)
stow --adopt zsh
# Option 3: Dry-Run für Details
stow -n -v zsh
Problem: “cannot stow over existing directory”
Ursache: Ein Verzeichnis existiert bereits und ist kein Symlink.
1
2
3
$ stow nvim
WARNING! stowing nvim would cause conflicts:
* existing target is a directory: .config/nvim
Lösungen:
1
2
3
4
5
6
7
8
9
10
# Option 1: Verzeichnis sichern und entfernen
mv ~/.config/nvim ~/.config/nvim.backup
stow nvim
# Option 2: --adopt verwenden
stow --adopt nvim
# Option 3: --no-folding für Datei-level Symlinks
rm -rf ~/.config/nvim # Vorsicht!
stow --no-folding nvim
Problem: Symlinks zeigen ins Nichts
Ursache: Paket wurde verschoben oder umbenannt.
1
2
$ ls -la ~/.zshrc
lrwxrwxrwx .zshrc -> dotfiles/zsh/.zshrc (broken)
Lösung:
1
2
3
# Restow mit korrekten Pfaden
cd ~/dotfiles
stow -R zsh
Debugging-Tipps
1
2
3
4
5
6
7
8
9
10
11
# Maximaler Verbose-Output
stow -vvv zsh
# Dry-Run mit Details
stow -n -vv zsh
# Symlink-Ziel prüfen
readlink ~/.zshrc
# Alle Symlinks im Home finden
find ~ -maxdepth 1 -type l -ls 2>/dev/null
Best Practices
1. Naming-Konventionen
1
2
3
4
5
6
7
8
9
# Gut: lowercase, beschreibend
zsh/
git/
nvim/
tmux/
# Vermeiden: Groß-/Kleinschreibung gemischt
ZSH/
NeoVim/
2. README im Dotfiles-Repo
Dokumentiere, welche Pakete verfügbar sind:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Meine Dotfiles
## Pakete
| Paket | Beschreibung | Dependencies |
|-------|--------------|--------------|
| zsh | Zsh-Konfiguration mit Oh-My-Zsh | zsh, oh-my-zsh |
| git | Git-Konfiguration | git |
| nvim | Neovim mit LazyVim | neovim >= 0.9 |
| tmux | tmux-Konfiguration | tmux |
## Installation
\`\`\`bash
git clone <repo> ~/dotfiles
cd ~/dotfiles
stow */
\`\`\`
3. .stowrc für Defaults
Erstelle eine .stowrc-Datei im Stow Directory für Standard-Optionen:
1
2
3
4
5
# ~/dotfiles/.stowrc
--target=/home/user
--ignore='README.*'
--ignore='LICENSE'
--ignore='\.git.*'
4. Git-Integration
1
2
3
4
5
# ~/dotfiles/.gitignore
*.backup
*.bak
*~
.DS_Store
5. Maschinenspezifische Konfiguration
Nutze Host-spezifische Pakete:
1
2
3
4
5
~/dotfiles/
├── zsh/ # Basis für alle Maschinen
├── zsh-work/ # Nur auf Arbeits-PC
├── zsh-server/ # Nur auf Servern
└── zsh-laptop/ # Nur auf Laptop
1
2
3
4
5
# Auf dem Arbeits-PC
stow zsh zsh-work
# Auf dem Server
stow zsh zsh-server
6. Install-Script
Automatisiere das Setup:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash
# ~/dotfiles/install.sh
DOTFILES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$DOTFILES_DIR"
# Alle Standard-Pakete
PACKAGES="zsh git tmux nvim"
echo "Installing dotfiles from $DOTFILES_DIR"
for pkg in $PACKAGES; do
if [ -d "$pkg" ]; then
echo "Stowing $pkg..."
stow -v "$pkg"
fi
done
echo "Done!"
Vergleich mit Alternativen
GNU Stow
Stärken:
- Keine Dependencies (reines Perl)
- Minimalistisch und schnell zu lernen
- KISS-Prinzip: macht eine Sache gut
- Perfekt für einfache Setups
Schwächen:
- Keine Templates
- Kein Secret-Management
- Multi-Machine nur über separate Pakete
Ideal für: Entwickler, die ein einfaches, robustes Tool wollen.
chezmoi
Stärken:
- Mächtiges Template-System (Go Templates)
- Secret-Management (1Password, Bitwarden, etc.)
- Multi-Machine mit Conditionals
- Diff-Ansicht vor Änderungen
Schwächen:
- Go-Binary erforderlich
- Steilere Lernkurve
- Komplexer für einfache Anwendungsfälle
Ideal für: Komplexe Multi-Machine Setups mit Secrets.
1
2
3
4
# chezmoi Beispiel
chezmoi init
chezmoi add ~/.zshrc
chezmoi apply
yadm
Stärken:
- Git-native (ist ein Git-Wrapper)
- Alternate Files für verschiedene Hosts
- Einfach wenn du Git kennst
- Bootstrap-Scripts
Schwächen:
- Requires Git (aber das hast du eh)
- Alternate Files können unübersichtlich werden
Ideal für: Git-Power-User, die ihre Dotfiles direkt in ~ verwalten wollen.
1
2
3
4
# yadm Beispiel
yadm init
yadm add ~/.zshrc
yadm commit -m "Add zshrc"
Wann welches Tool?
| Szenario | Empfehlung |
|---|---|
| Einfaches Setup, wenige Configs | GNU Stow |
| Multi-Machine mit gleichen Configs | GNU Stow (mit Paketen) |
| Templates für Host-spezifische Werte | chezmoi |
| Secret-Management erforderlich | chezmoi |
| Git-Power-User, direkte Home-Verwaltung | yadm |
| Minimale Dependencies | GNU Stow |
Cheat Sheet
Basis-Befehle
| Befehl | Beschreibung |
|---|---|
stow <pkg> |
Symlinks für Paket erstellen |
stow -D <pkg> |
Symlinks entfernen |
stow -R <pkg> |
Restow (Delete + Stow) |
stow */ |
Alle Pakete stow’en |
stow -n <pkg> |
Dry-Run |
stow -v <pkg> |
Verbose Output |
Pfad-Optionen
| Befehl | Beschreibung |
|---|---|
stow -d DIR <pkg> |
Stow Directory angeben |
stow -t DIR <pkg> |
Target Directory angeben |
stow -d ~/dotfiles -t ~ zsh |
Vollständiges Beispiel |
Fortgeschrittene Optionen
| Befehl | Beschreibung |
|---|---|
stow --adopt <pkg> |
Existierende Dateien ins Paket übernehmen |
stow --no-folding <pkg> |
Keine Verzeichnis-Symlinks |
stow --ignore='REGEX' <pkg> |
Dateien ausschließen |
stow --override='REGEX' <pkg> |
Konflikte überschreiben |
stow --defer='REGEX' <pkg> |
Konflikte überspringen |
Dateien
| Datei | Funktion |
|---|---|
.stowrc |
Default-Optionen |
.stow-local-ignore |
Ignore-Regeln pro Paket |
.stow-global-ignore |
Globale Ignore-Regeln |
Fazit
GNU Stow ist das perfekte Tool für alle, die ihre Dotfiles einfach und zuverlässig verwalten wollen. Mit einem einzigen Befehl ersetzt es dutzende manuelle ln -sf-Aufrufe und macht das Dotfiles-Management zum Kinderspiel.
Die wichtigsten Punkte:
- Struktur ist alles: Pakete müssen die Zielstruktur spiegeln
- Dry-Run nutzen: Immer erst mit
-ntesten - Einfach starten: Beginne mit wenigen Paketen und erweitere nach Bedarf
- Git nicht vergessen: Dotfiles gehören versioniert!
Mein Tipp: Starte mit einem einfachen Setup (zsh, git, tmux) und füge nach und nach weitere Pakete hinzu. Nach einer Woche wirst du dich fragen, wie du jemals ohne Stow ausgekommen bist!
Ressourcen
- GNU Stow Manual - Offizielle Dokumentation
- Dotfiles GitHub Guide - Community-Ressourcen
- Brandon Invergo’s Stow Guide - Klassisches Tutorial
- chezmoi - Alternative für komplexe Setups
- yadm - Git-basierte Alternative
