Skip to content

Repository files navigation

dotsync icon

dotsync

Set-and-forget dotfile sync for macOS and Linux.
Decide what's managed from any machine; every machine converges automatically.
Never silently overwrites a local change.

Documentation · Quick start · Download

CI Release Go Reference OpenSSF Scorecard License: MIT


$ dotsync init git@github.com:you/dotfiles.git
$ dotsync add ~/.config/fish/config.fish -d "Fish shell configuration"
managing ~/.config/fish/config.fish as 'fish/config.fish'
  sent      ~/.config/fish/config.fish
dotsync: 1 sent — pushed 1c049fe

$ dotsync status
dotsync on laptop: git@github.com:you/dotfiles.git (main @ 1c049fe)
last sync: 2026-09-21T11:16:09+05:30 (ok)
automatic sync: launchd agent loaded

SOURCE            TARGET                      STATUS    DESCRIPTION
fish/config.fish  ~/.config/fish/config.fish  ok        Fish shell configuration
gitconfig         ~/.gitconfig                CONFLICT  Git identity and aliases
nvim              ~/.config/nvim/             ok        Neovim

conflicts (neither version has been changed):
  ~/.gitconfig  since 2026-09-21T11:16:09+05:30
  inspect: dotsync diff <path>    settle: dotsync resolve <path> --keep local|remote
  (to merge by hand, edit the local file, then --keep local)

That's the whole workflow. From then on a background agent keeps every machine in sync. You only hear from dotsync when two machines changed the same file and it needs you to pick a version.

Why dotsync?

Most dotfile managers are deployment tools: you edit a repo, then run a command on each machine. dotsync is a synchronizer: edit the real file wherever you are, and it shows up everywhere else.

  • Automatic, both ways. Edit ~/.gitconfig on any machine and it propagates. Add or remove managed files from any machine too.
  • Safe by default. Local files are backed up before they are replaced or deleted. If two machines change the same file, both versions are kept and you get a conflict instead of a silent winner.
  • Secrets stay home. SSH keys, cloud credentials, tokens in shell rc files and similar things are refused before they reach the remote.
  • Offline-tolerant. Machines that were away for a month catch up correctly when they reconnect.
  • Few moving parts. One static binary plus git, and a private git repo you already know how to host. No daemon, database, server or account.
  • Light on your battery. A sync with nothing to do runs two git processes and writes nothing but a timestamp. There's no randomized scheduling and no surprise background work.
  • Portable. Targets are written as ~/… or $XDG_CONFIG_HOME/…. Per-OS entries and per-machine exclusions keep machine-specific settings out of the shared config.

Install

brew install pungoyal/tap/dotsync                                              # Homebrew (macOS, Linux)
curl -fsSL https://raw.githubusercontent.com/pungoyal/dotsync/main/install.sh | sh   # or the install script

On Ubuntu and Debian, install from the signed APT repository:

sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://pungoyal.github.io/dotsync/apt/dotsync.asc | sudo tee /etc/apt/keyrings/dotsync.asc >/dev/null
curl -fsSL https://pungoyal.github.io/dotsync/apt/dotsync.sources | sudo tee /etc/apt/sources.list.d/dotsync.sources >/dev/null
sudo apt update && sudo apt install dotsync

Homebrew and apt keep dotsync up to date like any other package.

The install script downloads the right binary for your OS and CPU and checks its SHA-256 checksum before installing it to ~/.local/bin. Later, dotsync update upgrades in place with the same checks. If the GitHub CLI is installed, it also verifies the build provenance attestation. See verifying releases.

Other ways to install

Prebuilt binaries and .deb packages: download from the releases page. Builds exist for macOS and Linux, on amd64 and arm64.

With Go 1.23+:

go install github.com/pungoyal/dotsync/cmd/dotsync@latest

From source:

git clone https://github.com/pungoyal/dotsync && cd dotsync && make build   # → bin/dotsync

Quick start

  1. Create an empty private repository on GitHub, GitLab or anywhere else you can reach with git. Make sure git clone works for it without a password prompt (an SSH key, or a credential helper).

  2. On your first machine:

    dotsync init git@github.com:you/dotfiles.git
    dotsync add ~/.gitconfig ~/.config/fish/config.fish ~/.config/nvim
  3. On every other machine, run the same init. Managed files show up. If a local file already existed and differed, it is backed up first and then replaced with the shared version.

  4. That's it. Edit files as you normally would; they sync every 5 minutes. Run dotsync doctor to check the setup, and dotsync status any time to see what's going on.

Follow the quick start for a guided tour.

How it works in 30 seconds

A private git repository holds a manifest: which files are managed, where they go, and what they are. It also holds their content. Every machine keeps a private record of the version it last agreed on with the remote (the base). Each sync compares three versions of every file:

local vs. base remote vs. base what dotsync does
same same nothing
same changed back up the local file, install the remote version
changed same push the local version
changed changed conflict: touch nothing, tell you

There are no git merges, rebases or clever heuristics. The full design is in How sync works.

Documentation

📖 pungoyal.github.io/dotsync

Quick start Two machines in sync in five minutes
Guides Managing files, conflicts, secrets, per-machine differences, migration
How sync works The model and its safety guarantees
Reference Commands, manifest, configuration, files, secret rules

Comparison

dotsync chezmoi yadm GNU Stow Mackup mise dotfiles
You edit the real file the source, or the file then chezmoi re-add the real file the real file, through its symlink the real file the real file, or the source for copied and templated files
Other machines get changes automatically when you run chezmoi update when you run yadm pull when you pull the directory when you run mackup restore automatically with the history watcher and history.sync = "sync", otherwise when you run mise dot sync
Same file changed on two machines per-file conflict: both kept, you choose git merge conflict in the source; asks before overwriting a file changed since the last apply git merge conflict git merge conflict, if the directory is a git repository whatever the storage provider does per-file conflict, but sync pauses for every tracked file until you choose
Secrets held back before upload templates that read password managers; encryption encryption not handled not handled encryption; credential files skipped by name
Differences per machine per-OS entries, per-machine exclusions templates alternate files, templates separate packages not handled templates, per-OS and per-profile variants

dotsync deliberately does not do templating. If you need one file to differ per machine in complicated ways, chezmoi is excellent. dotsync is for people who want their files to simply be the same everywhere, with no ceremony.

Contributing

Contributions are welcome. Please read CONTRIBUTING.md first. Security issues go through SECURITY.md, not public issues.

License

MIT

About

Set-and-forget dotfile sync for macOS and Linux: conflict-safe, secret-aware, automatic.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages