Skip to main content

dotsync

dotsync Python Platform License

Mirror-only dotfiles manager — edit configs in $HOME, mirror them to git, restore on new machines.

Install • Quick start • Commands • Filelist • Test coverage • Docs


dotsync watches paths under your home directory, copies their content into a git repo (default ~/.dotfiles), and pushes to a remote. Config files stay as regular files in $HOME — the repo is a mirror, not a symlink farm. Use categories to sync subsets of your dotfiles per machine; use @tree lines to watch whole directories that grow over time.

Installation

Quick install (installs uv if needed; first run ~30s, then instant):

curl -fsSL https://raw.githubusercontent.com/HarveyGG/dotsync/main/install.sh | bash

Homebrew:

brew tap HarveyGG/tap
brew install dotsync

pip:

pip install dotsync-cli

Requires git. Runtime uses uv to resolve the CLI (handled by the install methods above).

Quick start

Machine that already has your configs:

dotsync track ~/.zshrc shell
dotsync track ~/.config/nvim editor
dotsync save    # mirror → commit → push (prompts for remote on first push)

New machine:

dotsync restore
# or non-interactive:
dotsync restore --remote git@github.com:you/dotfiles.git --categories shell,editor --yes

track bootstraps ~/.dotfiles and git init on first use. restore clones (or uses an existing repo), pulls latest, then copies mirrors back to $HOME.

Filelist

Watch rules live in ~/.dotfiles/filelist:

# path:category[,category...]  optional |encrypt
.zshrc:shell,common
.ssh/config:tools|encrypt

# whole directory — re-scanned on every save
@tree:.config/nvim:editor
@tree:.local/share/my-app/custom-*:tools

# host → category groups (optional)
macbook=shell,editor,common
  • Atomic paths — single files tracked with dotsync track <file>.
  • @tree — whole directories; dotsync track <dir> adds a @tree line. New files under the pattern are picked up on the next save. Globs supported (*, ?, […]).
  • Symlinks inside trees — targets are materialized into the repo (internal links keep layout; external targets go under .dotsync/materialized/).

Commands

Command Description
init [dir] Create repo skeleton at ~/.dotfiles (or given path)
track <path> [category] [--encrypt] [--no-auto-update] Add to filelist; mirrors immediately unless --no-auto-update
untrack <path> [--purge-repo] Stop watching; home file kept
encrypt <path> Convert an already-tracked plain path to encrypted
list [categories] [--top-level] List watched paths; each row shows (file|tree, plain|encrypt) plus categories; @tree entries are summarized by directory, not expanded
categories Show category groups from filelist
save [categories] [-m msg] [--dry-run] [--no-push] Expand @tree, mirror home → repo, commit, push
restore [categories] [--remote URL] [--yes] [--skip-pull] [--conflict …] Pull (unless skipped), then repo → home; diff on conflict
update [categories] Mirror home → repo without commit
diff [categories] Show git diff plus pending mirror changes
commit [-m msg] Commit staged repo changes
clean [categories] Remove repo mirrors no longer in filelist
passwd Set or change encryption password
showpw Print stored encryption password (local machine only)

Common flags: --non-interactive, --dry-run, --encrypt, --keep-going.

Full reference: ReadTheDocs.

Test coverage

295 tests total (37 black-box E2E scenarios against the real CLI in an isolated sandbox). All scenarios below pass on v2.0.5.

uv run pytest tests/blackbox/ -v
uv run pytest tests/ -v
ID Area What it verifies
L1 Lifecycle track → save (push) → restore on a fresh machine
L2 Lifecycle untrack removes from filelist; home file kept
L3 Lifecycle untrack --purge-repo deletes mirror
L4 Lifecycle track bootstraps repo when missing
L5a Lifecycle Default track mirrors immediately
L5b Lifecycle track --no-auto-update defers mirror until save
M1 Mirror Home paths stay regular files after save + restore
M2 Mirror Atomic file round-trip is byte-identical
M3 Mirror Nested paths restore as files, not symlinks
RP1 Pull restore pulls remote before copying to home
RP2 Pull Diverged repo aborts restore with no home writes
RP3 Pull --skip-pull uses local HEAD only
RP4 Pull No remote: restore from local HEAD
C1 Conflicts Cancel on diff aborts entire restore
C2 Conflicts Overwrite continues for remaining paths
C3 Conflicts Identical home file skipped without prompt
C4 Conflicts --conflict overwrite --non-interactive
C5 Conflicts --conflict abort --non-interactive
T1 @tree New tree member picked up on second save
T2 @tree Glob excludes non-matching paths
T3 @tree Removed member pruned from repo mirror
T4 @tree Tree save → restore on clean home
S1 Symlinks Internal symlink materialized with manifest
S2 Symlinks External symlink under .dotsync/materialized/
S3 Symlinks Broken symlink skipped cleanly
S4 Symlinks Dedup when link target also watched
S5 Symlinks Restore recreates internal symlink
S6 Symlinks External symlink save → restore round-trip
E1 Encrypt Encrypt track → save → restore
E2 Encrypt showpw prints stored password
E3 Encrypt showpw fails when no password set
B1 Boundaries Empty filelist save is a no-op
B2 Boundaries Declined remote URL aborts save
B3 Boundaries Push failure exits non-zero
B4 Boundaries Binary conflict; cancel leaves home unchanged
B5 Boundaries --no-push durability warning
B6 Boundaries Save without remote exits quickly (no hang)

Scenario details: tests/blackbox/test_plan.md.

Contributing

git clone https://github.com/HarveyGG/dotsync.git && cd dotsync
uv sync
uv run pytest tests/

Pull requests welcome.

License

Non-Commercial License — free for personal, educational, and non-profit use. See LICENSE. Commercial use requires permission: harvey.wanghy@gmail.com

Links

Metadata

Release files for dotsync-cli 2.0.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dotsync-cli 2.0.6
File Size Uploaded
dotsync_cli-2.0.6.tar.gz 39.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dotsync-cli 2.0.6
File Interpreter ABI Platform
dotsync_cli-2.0.6-py3-none-any.whl Python 3 none any Details

Total release size: 84.0 kB

Release files / dotsync_cli-2.0.6.tar.gz

Download URL dotsync_cli-2.0.6.tar.gz
Size 39.5 kB
Tags Source
SHA-256 checksum
How to use checksums
254c7fc03ab147cf92dfe3e6d93bfab592b14a49837a25887102e27631171ac7
BLAKE2b-256 checksum
How to use checksums
1fe81aeef2b851109307c5ccc6e8c6ecaa08bcf1feddd6d5bcdf64236f271129
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / dotsync_cli-2.0.6-py3-none-any.whl

Download URL dotsync_cli-2.0.6-py3-none-any.whl
Size 44.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0db0d61d31aa14f2d5d6b75ef927f39fcabf58edcd4ce08ed70bec229e5520c0
BLAKE2b-256 checksum
How to use checksums
112e287eb9af064465da6132a98f665a0ba5970984a828c3bce8be48d68be265
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

2.0.6 This release

2 release files

2.0.5

2 release files

2.0.4

2 release files

2.0.3

2 release files

2.0.2

2 release files

1.0.15

2 release files

1.0.14

2 release files

1.0.13

2 release files

1.0.9

2 release files

1.0.8

2 release files

1.0.7

2 release files

1.0.6

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page