Sync selective folders from Git repositories to a target directory
Project description
syncware
A CLI tool for syncing selective folders from local Git repositories to a target directory. Think go mod vendor or npm install, but for folder-based content.
Installation
pip install syncware
Development
Clone the repository and install with dev dependencies using uv:
git clone https://github.com/youruser/syncware.git
cd syncware
uv sync --group dev
This installs build, twine, and pytest for building and testing.
Quick Start
# Initialize a new project
syncware init
# Edit syncware.yml with your repositories
# List configured folders
syncware list
# Sync folders to target
syncware sync
# Preview sync (dry run)
syncware sync --dry
# Update repos and sync
syncware update
# Generate lockfile (captures exact versions)
syncware lockfile
# Verify folders against lockfile
syncware verify
# Auto-fix drift
syncware verify --fix
Verbosity
syncware -v list # INFO level (default)
syncware -vv list # DEBUG level
Configuration
Create a syncware.yml file in your project root:
repos:
- name: myrepo
path: /path/to/local/repo
source: path/to/folders
items:
- folder1
- file.txt
- "*" # or all items (files and subdirectories)
target: ./output # optional, overrides global target
target: ./output # global target (required)
Target Required
A target must be set at the global level, per-repo level, or per-source level. If no target is found at any level, sync will error:
# Error: Repo 'myrepo' has no target configured
syncware sync
Per-Repo Target
Each repo can have its own target:
repos:
- name: frontend
path: ./packages/frontend
source: dist
items: ["ui", "icons"]
target: ./public/assets
- name: backend
path: ./packages/backend
source: configs
items: ["nginx", "docker"]
target: ./deploy/config
target: ./common/output # used by repos without own target
Multiple Sources Per Repo
A single repo entry can sync from multiple source directories, each with its own items and optional per-source target:
repos:
- name: myrepo
path: /path/to/repo
sources:
- source: skills
items: ["folder1", "folder2"]
target: ./output1 # optional, overrides repo/global target
- source: docs
items: ["readme", "api"]
target: ./output2
This is equivalent to:
# Legacy single-source format (still fully supported)
repos:
- name: myrepo
path: /path/to/repo
source: skills
items: ["folder1", "folder2"]
target: ./output1
YAML Variables (Anchor & Alias)
YAML anchors and aliases let you define a value once and reuse it across multiple repos:
# Define reusable values
shared_target: &shared_target ~/Downloads/output
backup_target: &backup_target ./backup
repos:
- name: frontend
path: ./packages/frontend
source: dist
items: ["ui", "icons"]
target: *shared_target
- name: backend
path: ./packages/backend
source: configs
items: ["nginx", "docker"]
target: *shared_target
- name: docs
path: ./docs
source: build
items: ["html"]
target: *backup_target
Clean Item
When clean_item_content: true, synchronizes target folders to exactly match source by removing any extra files/directories that exist in target but not in source. Can be set globally or per-repo:
clean_item_content: true # global setting
repos:
- name: myrepo
path: ./repo
source: dist
items: ["ui", "icons"]
clean_item_content: false # repo-level override
Ignore Hidden Files and Folders
By default, all files are synced including hidden ones (starting with .). Set ignore_hidden_file or ignore_hidden_folder to true to exclude them:
ignore_hidden_file: true # skip hidden files (starting with .)
ignore_hidden_folder: true # skip hidden directories (starting with .)
repos:
- name: myrepo
path: ./repo
source: dist
items: ["ui", "icons"]
ignore_hidden_file: false # repo-level override
Keep Existing Item
When keep_existing_item: false, removes folders in the target root that aren't configured to sync. Default is true (keeps extra folders):
keep_existing_item: false # global setting
repos:
- name: myrepo
path: ./repo
source: dist
items: ["ui", "icons"]
keep_existing_item: true # repo-level override
Multiple Targets
Both global and per-repo targets can specify multiple destinations:
# Global multiple targets
target: ["./output1", "./output2"]
repos:
- name: myrepo
path: /path/to/repo
source: dist
items: ["ui", "icons"]
# folder1 and folder2 sync to BOTH ./output1 and ./output2
# Per-repo multiple targets
repos:
- name: frontend
path: ./packages/frontend
source: dist
items: ["ui", "icons"]
target: ["./public/assets", "./backup/assets"]
# ui and icons sync to BOTH ./public/assets and ./backup/assets
Remote Repositories
You can also use remote Git URLs (GitHub, GitLab, etc.):
repos:
- name: claude
path: https://github.com/user/repo.git
source: skills
items: ["docx", "xlsx"]
Remote repos are cloned to ~/.cache/syncware/<name> and reused on subsequent runs.
Config Fields
| Field | Description |
|---|---|
repos |
List of source repositories |
repos[].name |
Namespace identifier |
repos[].path |
Local path or Git URL |
repos[].source |
Subdirectory containing folders to sync (single-source format) |
repos[].sources |
List of source entries, each with source, items, optional target (multi-source format) |
repos[].items |
List of folder or file names, or "*" for all |
repos[].target |
Per-repo destination (string or list, overrides global) |
repos[].clean_item_content |
Remove extra files in synced folders not in source (overrides global) |
clean_item_content |
Global clean setting (removes extra files in synced folders) |
repos[].ignore_hidden_file |
Skip hidden files starting with . (overrides global) |
ignore_hidden_file |
Global ignore hidden files setting |
repos[].ignore_hidden_folder |
Skip hidden directories starting with . (overrides global) |
ignore_hidden_folder |
Global ignore hidden folders setting |
repos[].keep_existing_item |
Keep extra folders in target root not in config (overrides global) |
keep_existing_item |
Global keep setting (removes extra folders in target root) |
target |
Global destination directory (string or list) |
How It Works
<repo.path>/<source>/<folder> → copied to <repo.target>/<folder>
or <global.target>/<folder>
(or to ALL targets if multiple)
Lockfile
The lockfile (syncware.lock.yml) ensures reproducible syncs:
syncware lockfile # Generate lockfile
syncware verify # Check for drift
syncware verify --fix # Auto-fix drift
What gets locked:
- Git commit hash of each source repository
- Content hash (SHA256) of each synced folder
Verification detects:
DRIFT- Folder content was modified locallyUPDATE_AVAILABLE- Source repo has new commitsMISSING- Source folder was deleted
Use Cases
- Skills/Plugins - Sync skill folders from a central repo
- Config Management - Keep config folders in sync across machines
- Documentation - Maintain a set of doc folders from different sources
- Assets - Bundle asset folders from multiple repositories
Comparison
| Tool | Use Case |
|---|---|
syncware |
Selective folder sync from local or remote repos |
go mod vendor |
Vendor Go dependencies |
npm install |
Install package dependencies |
rsync |
General file/folder synchronization |
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file syncware-0.0.9.tar.gz.
File metadata
- Download URL: syncware-0.0.9.tar.gz
- Upload date:
- Size: 10.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
99fa45a313a200fbacd82a4798e11013aac8e21ef8d87441b61c9de5f521080f
|
|
| MD5 |
61dc62451e6665ab875b55e59541dcc2
|
|
| BLAKE2b-256 |
0f81459fdd69ddfce469ea6d6802a6384d7f0134364712e2d12323b0cb203536
|
File details
Details for the file syncware-0.0.9-py3-none-any.whl.
File metadata
- Download URL: syncware-0.0.9-py3-none-any.whl
- Upload date:
- Size: 14.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa95bf9e4fffa875697768ee5dda66ed7031104392dc1f010c770556e1d7db1c
|
|
| MD5 |
d2fcf88553b0e6c1a4fe8f6e17bc1aaf
|
|
| BLAKE2b-256 |
1e00137b7bd2416ba92d9b1afbcdac4550da8d66f469f578136f4d602d18a5e7
|