Manage files and directories
The commands on this page change the shared manifest, so they apply to every machine, whichever machine you run them on. Each one syncs straight away, so you see the result. add, remove and set also accept --no-sync, which only queues the change for the next sync.
Add a file
Section titled “Add a file”dotsync add ~/.gitconfig -d "Git identity and aliases"The file is copied into the repository and pushed. Every other machine installs it on its next sync, backing up any copy it already has first. (A machine set up with init --keep-existing reports a different existing copy as a conflict instead.)
The source, the file’s location under files/ in the repository, comes from its path: a leading .config/ is dropped, and so are the leading dots of what remains. ~/.gitconfig becomes gitconfig, and ~/.config/fish/config.fish becomes fish/config.fish. To choose one yourself:
dotsync add ~/.config/git/config --source git/config -d "Git (XDG location)"Without -d, the description is the file name. You can add several paths at once, as in dotsync add ~/.vimrc ~/.inputrc, but -d and --source only work with a single path.
Add a directory
Section titled “Add a directory”dotsync add ~/.config/nvim -d "Neovim" --ignore lazy-lock.json --ignore 'spell/*.spl'A directory is managed recursively: files added, changed or deleted anywhere inside it sync too. Symlinks inside it are synced as symlinks, and each file’s executable bit is kept. Empty directories aren’t tracked.
These are always skipped: .DS_Store, ._*, *.swp, *.swo, *~, .#*, .git, __pycache__, *.pyc, .dotsync-tmp-*. The last one is the temporary file dotsync writes while replacing a file.
Directory~/.config/nvim/ managed as
nvim- init.lua synced
Directorylua/
- plugins.lua synced
- lazy-lock.json skipped:
--ignore lazy-lock.json Directoryspell/
- en.utf-8.spl skipped:
--ignore 'spell/*.spl'
- en.utf-8.spl skipped:
- .DS_Store always skipped
Choosing what to ignore
Section titled “Choosing what to ignore”Anything generated, machine-specific or large doesn’t belong in sync: plugin checkouts, caches, lock files that differ per machine, logs, sockets.
A pattern is matched against each file’s name and against its path inside the directory, and against every directory above the file too, so a pattern that matches a directory skips everything below it. * also matches /, ? matches one character, and […] a character class. Quote patterns so your shell doesn’t expand them.
| Pattern | Skips |
|---|---|
lazy-lock.json |
any file or directory named lazy-lock.json, at any depth |
spell/*.spl |
.spl files under spell/ at the top of the directory |
plugin |
a plugin directory at any depth, and everything in it |
*.log |
every file whose name ends in .log |
Credential files inside a directory
Section titled “Credential files inside a directory”Credential files in a managed directory aren’t refused. They’re held back: never uploaded, and reported as BLOCKED by sync and status. add warns about them up front:
dotsync add ~/.config/gh -d "GitHub CLI"
note: 1 file(s) under ~/.config/gh look like secrets and will not be sent (e.g. hosts.yml)
managing ~/.config/gh as 'gh'
sent ~/.config/gh/config.yml
BLOCKED ~/.config/gh/hosts.yml (path looks like a secret (matches '.config/gh/hosts.yml'))
dotsync: 1 sent, 1 blocked — pushed 0c9c9a4To stop seeing them, ignore them: dotsync set ~/.config/gh --ignore hosts.yml. See Keep secrets out.
What can’t be added
Section titled “What can’t be added”add refuses:
- paths outside your home directory, and your home directory itself
- dotsync’s own directories:
~/.config/dotsync,~/.local/share/dotsyncand~/.local/state/dotsync - anything that isn’t a regular file or a directory, such as a socket
- a path that’s already managed, unless both entries are limited to different operating systems
- a path inside a managed directory, or a directory containing a managed path
- a source already used by another entry, or one that overlaps another source
- files that look like secrets; see Keep secrets out
If the path you add is a symlink, as in an old GNU Stow setup, dotsync keeps the link and syncs the file or directory it points to, which must also be inside your home directory. Files larger than 10 MiB can’t be synced: add refuses such a file, and inside a managed directory it’s reported as an error while the rest of the directory syncs normally.
Change an entry
Section titled “Change an entry”dotsync set changes an entry for every machine. Name the entry by its path on this machine or by its source:
dotsync set ~/.config/nvim --ignore lazy-lock.json # skip another filedotsync set ~/.config/nvim --unignore lazy-lock.json # sync it againdotsync set ~/.ssh/config --mode 0600 # force these permissions everywheredotsync set karabiner/karabiner.json --os darwin # manage it on macOS onlydotsync set ~/.gitconfig -d "Git identity, aliases and signing"dotsync set nvim --ignore 'spell/*.spl' --mode 0600
updated 'nvim': mode = 0600; ignore + spell/*.spl
dotsync: in sync (12 files) — pushed 4e1d2a7Changes are checked before anything is queued, so an invalid mode or OS is refused straight away. Ignore patterns are recorded as additions and removals, so if two machines change them at the same time, both changes survive. set lists every option; dotsync describe <entry> <text> is a shortcut for set <entry> -d <text>.
set can’t change an entry’s source or target. To move one, remove it and add it again.
Permissions
Section titled “Permissions”Without --mode, each machine keeps its own permissions for a file, and only the executable bit syncs. With --mode 0600, every machine gives the file exactly those permissions whenever dotsync writes it there, which is what you want for files like ~/.ssh/config. A copy that’s already up to date keeps its current permissions until dotsync next writes it. --no-mode goes back to the default.
How files are written
Section titled “How files are written”By default, dotsync replaces a file atomically: it writes a temporary file next to it and renames it into place, so no program ever sees a half-written file. A few programs track a file by its inode, and a container that bind-mounts a single file keeps seeing the old one after a rename. For those, --write inplace rewrites the existing file instead.
Stop managing something
Section titled “Stop managing something”dotsync remove ~/.tmux.conf
no longer managing ~/.tmux.conf ('tmux.conf'); local copies are left in place on every machine
dotsync: in sync (14 files) — pushed 9a3f6b0This stops managing the entry on every machine. The file itself stays exactly where it is on every machine, as an ordinary file that dotsync no longer touches. Its content stays in the repository’s history.
Work offline
Section titled “Work offline”Every command on this page works without a network connection. The change is queued on this machine, shown as queued, not yet pushed by dotsync status, and sent by the first sync that reaches the remote. Queued changes are replayed on top of whatever the other machines pushed in the meantime, so two machines can add different files at the same moment without either change being lost.
Edit the manifest by hand
Section titled “Edit the manifest by hand”You can also edit manifest.json directly in any clone of your dotfiles repository, commit and push. That’s handy for bulk changes. Machines pick the change up on their next sync. The manifest reference lists every field.