


























I have gone through a few generations of dotfile management over the years: hand-written setup scripts, ad-hoc symlinks, shell aliases, Stow and friends, and the usual “I will clean this up later” folder structures. They all worked until I eventually ran into annoying issues.
What I wanted was fairly specific:
~/.config/ or /etc/openvpn/ into all-or-nothing symlinks.That set of constraints is what led me to build dloom. It is a small CLI for linking, unlinking, and adopting dotfiles.
Traditional dotfile management is easy when every config file can be treated the same way. In practice, many of my configs require custom conditional handling.
Some configs belong on every machine. Some should only exist on Linux. Some depend on whether tmux, sway, or hyprland is installed. Some need different source files but the same target name. And some target directories are shared with applications that create their own files, caches, or local state.
Directory-level symlinking is nice when the directory is entirely yours. It gets awkward when you want to manage only a few files inside a directory that other programs also touch. ~/.ssh, ~/.config, /etc/openvpn, and similar paths are full of that kind of overlap. I wanted a tool that linked files individually while leaving the surrounding files in the directory as regular files not owned in my dotfiles repo.
A recent concrete example for me was moving to Omarchy. I liked the overall setup, but I did not want to hijack the entirety of ~/.config/hypr/ just to override a few files that I cared about. I wanted Omarchy to keep owning the rest of that directory while my dotfiles repo only managed the pieces I intentionally replaced or overrode.
The core idea is simple: dloom symlinks files, not directories.
If I have a dotfile repo like this:
~/dotfiles/
└── zsh/
├── .zshenv
└── .config/
└── zsh/
└── aliases.zsh
and I run:
I get this:
~/
├── .zshenv -> ~/dotfiles/zsh/.zshenv
└── .config/
└── zsh/
└── aliases.zsh -> ~/dotfiles/zsh/.config/zsh/aliases.zsh
The parent directories stay real directories. Only the files become symlinks. That means other programs can keep writing their own files into .config/zsh/ without fighting the dotfile manager.
There is a trade-off and I am happy with it: if I add a new file to the package later, I rerun dloom link so the corresponding symlink gets created. I prefer that explicit step to handing over the whole target directory to a directory-level symlink.
That one design choice is the entire reason this tool exists.
dloom has three main workflows.
This creates symlinks from a package in the source repo into the target directory:
There is also a dry-run mode, which is useful when I am changing a lot of files or bringing up a new machine:
dloom -d link zsh tmux nvim
This removes only the symlinks that point back into the configured source repo. It does not blindly remove files from the target machine.
If dloom backed up something before replacing it, unlink can restore that backup.
This is the command I wanted during the initial migration from hand-managed dotfiles.
If I already have a real file on disk and want to bring it under management, adopt moves it into the source package and replaces it with a symlink:
dloom adopt zsh ~/.zshrc
dloom adopt ghostty ~/.config/ghostty
That makes migration much less annoying than manually copying files around and then relinking them.
Once you keep one dotfiles repo across multiple machines, conditions become unavoidable.
A few common cases:
tmux config only if tmux is actually installed.fzf shell exports on Ubuntu and Arch because the packaged versions behave differently.dloom lets me express those rules in YAML instead of burying them in shell scripts.
For example, this kind of setup lets me keep separate source files for macOS and Linux while still targeting the same final file name:
link_overrides:
zsh:
file_overrides:
".zshrc_linux": # the file in my dotfiles repo; meant for linux
target_name: ".zshrc"
conditions:
os:
- "linux"
".zshrc_mac": # the file in my dotfiles repo; meant for my Mac laptop
target_name: ".zshrc"
conditions:
os:
- "darwin"
The same mechanism works for executable checks, distro checks, user-specific files, and hostname-specific files.
That has been much easier to reason about than carrying around a pile of bootstrap scripts full of conditionals.
A minimal repository can look like this:
~/dotfiles/
├── fzf/
│ ├── exports.arch.zsh
│ └── exports.ubuntu.zsh
├── zsh/
│ ├── .zshrc_linux
│ └── .zshrc_mac
├── tmux/
│ └── tmux.new.conf
└── dloom/
└── config.yaml
With a matching dloom/config.yaml, I can say:
fzf export snippets on Ubuntu and Arch, because the Ubuntu package is old enough that the shell integration differs from the newer Arch package..zshrc_linux as ~/.zshrc on Linux..zshrc_mac as ~/.zshrc on macOS.tmux.new.conf to tmux.conf and only link it when the installed tmux version is new enough.dloom itself inside the same repo.That gives me one repository, one CLI, and much less machine-specific glue.
If you want to try it, the easiest options are Homebrew or go install. It is also available in the Arch AUR. I am trying to get it into the Snap repository but given that this requires access to a user’s home-directory, it is unlikely that the submission will be accepted.
brew tap dloomorg/dloom https://github.com/dloomorg/dloom
brew install dloomorg/dloom/dloom
or:
go install github.com/dloomorg/dloom
There are also prebuilt binaries and example configurations in the repository.
I did not want a very ambitious dotfile framework. I wanted a small tool that handled the annoying parts well:
If your current dotfile setup is a mix of fragile symlinks, one-off shell scripts, and “I should clean this up later” logic, dloom might be useful. The README has more detailed examples, but the mental model is intentionally small: organize files into packages, describe exceptions in YAML, and let the tool do the tedious part.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。