Skip to content

Per-OS and per-machine differences

dotsync makes files identical everywhere they’re managed, and deliberately has no templating. When machines genuinely need to differ, these are your tools, from the simplest to the most flexible.

Terminal window
dotsync add ~/.config/karabiner/karabiner.json --os darwin -d "Keyboard remapping"
dotsync set ~/.config/karabiner/karabiner.json --os darwin # for an entry that already exists
dotsync set ~/.config/karabiner/karabiner.json --any-os # undo

Machines running another OS skip the entry: they neither read nor write the file, and status shows why:

dotsync status
…
SOURCE                    TARGET                              STATUS   DESCRIPTION
karabiner/karabiner.json  ~/.config/karabiner/karabiner.json  skipped  Keyboard remapping
                                                              ↳ only for darwin

Add an OS-specific entry on a machine running that OS, so the file is uploaded straight away. Added elsewhere, the entry is created empty, and the first matching machine to sync uploads its copy.

To have, say, one alacritty.toml on your Macs and another on your Linux machines, use two entries with the same target, different sources, and one OS each. Add each one on a machine running its OS, so its file is uploaded straight away:

Terminal window
# on a Mac
dotsync add ~/.config/alacritty/alacritty.toml --source alacritty/macos.toml --os darwin
# on a Linux machine
dotsync add ~/.config/alacritty/alacritty.toml --source alacritty/linux.toml --os linux

The manifest then holds:

manifest.json (excerpt)
{
"source": "alacritty/macos.toml",
"target": "~/.config/alacritty/alacritty.toml",
"description": "Alacritty (macOS)",
"os": ["darwin"]
},
{
"source": "alacritty/linux.toml",
"target": "~/.config/alacritty/alacritty.toml",
"description": "Alacritty (Linux)",
"os": ["linux"]
}

Each machine only manages the entry for its own OS, so the two never meet. Two entries can only share a target when their OS lists don’t overlap. On each machine, the path names the entry for that machine’s OS, so dotsync set ~/.config/alacritty/alacritty.toml … changes the right one; use the source to change the other.

Versions of dotsync before this was possible refuse the second add. With those, add the second entry to manifest.json by hand; the first matching machine to sync uploads its file.

On the machine that shouldn’t have it:

dotsync exclude ~/.config/karabiner/karabiner.json
'karabiner/karabiner.json' is no longer managed on this machine; its local files are left as they are
dotsync: in sync (14 files)

dotsync exclude
excluded on this machine: karabiner/karabiner.json
Terminal window
dotsync include ~/.config/karabiner/karabiner.json # manage it here again

The machine stops managing the entry. Its local file stays exactly as it is, and the other machines aren’t affected. Exclusions are stored in this machine’s configuration, never in the shared manifest.

When you include an entry again and the local file differs from the shared version, it’s treated like a file on a new machine: backed up and replaced, or reported as a conflict if the machine uses --keep-existing.

Many programs can include a second file. Sync the main file, and keep a small unmanaged file next to it for what’s specific to each machine:

Program In the synced file Local file
git [include] path = ~/.gitconfig.local ~/.gitconfig.local
ssh Include ~/.ssh/config.local, at the top ~/.ssh/config.local
zsh, bash [ -f ~/.zshrc.local ] && . ~/.zshrc.local ~/.zshrc.local
fish test -f ~/.config/fish/local.fish; and source ~/.config/fish/local.fish ~/.config/fish/local.fish
tmux source-file -q ~/.tmux.local.conf ~/.tmux.local.conf
Neovim pcall(require, 'local') ~/.config/nvim/lua/local.lua
mise files in conf.d/ are loaded automatically ~/.config/mise/conf.d/local.toml

If the local file sits inside a managed directory, as the Neovim, fish and mise ones would when the whole directory is managed, ignore it: dotsync set ~/.config/nvim --ignore lua/local.lua.

Some tools write the absolute path of a program into your config files. Synced to a machine where the program lives somewhere else, the setting breaks there.

The usual case is gh auth setup-git, which writes

~/.gitconfig, as written by gh on Linux
[credential "https://github.com"]
helper = !/usr/bin/gh auth git-credential

On a Mac, gh is usually in /opt/homebrew/bin, so git there can no longer authenticate to GitHub over HTTPS, and if your dotfiles remote uses HTTPS, dotsync can’t sync either. dotsync doctor, status and the agent’s notification all name the setting and the file it’s in.

Fix it in either of two ways:

  • Name the program without its path, so each machine finds its own copy on its PATH:

    ~/.gitconfig
    [credential "https://github.com"]
    helper =
    helper = !gh auth git-credential
  • Keep machine-specific settings in a local file that isn’t synced, and include it from the shared one (see above).

Make the edit on the machine where it’s broken; the next sync sends the fix everywhere.

Write targets in a portable form: ~/…, or $XDG_CONFIG_HOME/… if some machines move their config directory. Each machine expands them itself. Absolute paths aren’t allowed in the manifest, because they differ between machines. See targets.