Stow symlinks a central config directory into place; nothing is copied, so editing ~/.zshrc edits the repository file.
sudo apt install stow # Debian, Ubuntu
sudo pacman -S stow # Arch
brew install stow # macOS
Each package mirrors the target:
~/dotfiles/
├── zsh/.zshrc
├── git/.gitconfig
└── nvim/.config/nvim/init.lua
cd ~/dotfiles
stow zsh
stow zsh git nvim
stow */
Exact structure: zsh/zshrc links nothing, zsh/.zshrc does. Preview with a dry run:
stow -n -v zsh
What it links in .config
nvim/.config/nvim/init.lua in the repository makes stow nvim produce:
~/.config/nvim -> ~/dotfiles/nvim/.config/nvim
Stow links nvim inside .config, not .config itself, avoiding an existing directory; with ~/.config absent it may link all of it.
To force targeting .config, restructure and say so:
dotfiles/nvim/nvim/init.lua
stow --target=$HOME/.config nvim
-t targets any other destination, e.g. bin/ to ~/scripts:
stow -t ~/scripts bin
Conflicts and adoption
An existing target makes Stow refuse rather than overwrite: move it aside, or let Stow move it into the repository:
mv ~/.zshrc ~/.zshrc.bak
stow --adopt zsh
--adopt is convenient once, dangerous run blindly: it overwrites the repository copy with the home directory version.
Undoing
stow -D zsh # remove the links
stow -D .
stow -R zsh # restow: delete and recreate
Deleting the symlink by hand is equivalent; the repository file is untouched, and Stow only creates symlinks. Check first: rm deletes files as readily as links:
ls -l ~/.config # the -> arrow marks a symlink
stow -D is safer when many links exist and you do not know which Stow created.
Multiple machines
Layout: a shared base plus per-machine packages:
dotfiles/
├── common/
├── machines/{desktop,laptop,server}/
└── install.sh
HOST=$(hostname)
stow common
[ -d "machines/$HOST" ] && stow "machines/$HOST"
common always applies, the machine package only where it exists; OS variation goes in separate packages, not conditionals in one file. .stow-local-ignore excludes files from a package when some should not be linked.