Bidirectional dotfile synchronization between $HOME and a Git repository with confirm-before-overwrite protection and automatic backups.
- About the Project
- Getting Started
- Usage
- Tracked Files
- Configuration
- Backup System
- Included Utilities
- Contributing
- License
- Acknowledgments
dot-sync is a safe, bidirectional synchronization tool for managing dotfiles and configuration files across multiple machines. It keeps your configurations version-controlled while providing interactive confirmation and automatic backups before any potentially destructive operations.
- Safe overwrite protection: Interactive diff preview and confirmation before any file modifications
- Automatic timestamped backups: Changed files are backed up to
.bak/<filename>/bak.YYYY-MMDD-HHMMSSbefore overwrite - Bidirectional sync: Pull from repo to local (
$HOME) or push from local to repo - Status checking: View differences between your local files and the repository without making changes
- Smart git integration: Automatically commits changes using AI-generated messages via
git-ai-commit - Executable preservation: Automatically maintains
+xpermissions on.local/binscripts - Flexible path mappings: Support for custom directory mappings (e.g., macOS
Library/Application Support)
- The script tracks a predefined list of dotfiles and utilities in the
FILESarray - Each file can be synced either by name (implicit mapping) or with explicit
local_path => repo_pathsyntax - Before overwriting any file, the script shows a diff and asks for confirmation
- All overwrites create timestamped backups in
.bak/<filename>/ - On
push, changes are automatically committed usinggit-ai-commitand pushed to the remote repository - Color-coded diffs are shown when
colordiffis available
- Bash 4.0+
- Git
- Optional:
colordifffor colorized diff output# macOS brew install colordiff # Linux (Debian/Ubuntu) apt-get install colordiff
- Optional:
llmCLI for AI-powered commit messagespip install llm llm keys set openai # Configure your OpenAI API key
-
Clone the repository:
git clone https://github.com/adambossy/dot-sync.git ~/code/dot-sync cd ~/code/dot-sync
-
Make the script executable:
chmod +x dot-sync
-
Add to your
PATHfor easy access (add to~/.bashrcor~/.zshrc):export PATH="$PATH:$HOME/code/dot-sync"
-
Verify installation:
dot-sync --help
Common workflows:
# 1) Check status and see what's different
dot-sync status # or: dot-sync diff
# 2) Pull files from repo to local (with confirmation)
dot-sync pull
# 3) Push files from local to repo, then auto-commit and push to remote
dot-sync push-
dot-sync statusordot-sync diff
Show differences between repo and local files. No modifications are made.
Exit code:0if no differences,1if differences found. -
dot-sync pull
Copy files from repository → local ($HOME).- Shows diff for each changed file
- Prompts for confirmation before overwrite
- Creates timestamped backups of modified files
- Automatically sets
+xon.local/binexecutables
-
dot-sync push
Copy files from local ($HOME) → repository, then commit and push.- Shows diff for each changed file
- Prompts for confirmation before overwrite
- Creates timestamped backups of modified files
- Runs
git add -Ato stage all changes - Uses
git-ai-committo generate an AI commit message - Pushes to the remote
origin(sets upstream if needed)
- Files must exist in the source location to be synced (missing files are skipped with a log message)
- If repo and local files are identical, the operation is skipped with a "No change" message
- Pressing anything other than
yorYwhen prompted will skip that file - The
DOTSYNC_REPOenvironment variable can override the repo directory location
The following files are automatically synced by default:
Dotfiles:
~/.vimrc~/.bashrc~/.git-completion.bash~/.gitconfig~/.inputrc~/.sdirs
Local utilities (~/.local/bin/):
git-ai-commit— Generate AI-powered commit messagesgit-clean-local-branches— Clean up merged and stale branchesgit-clean-rebase— Interactive rebase cleanup toolconvert-heics-to-jpgs— Bulk HEIC to JPEG converterorganize-files— AI-powered file organizer for Documents directory
macOS-specific:
~/Library/Application Support/Amethyst/Layouts/centered-primary-columns.js~/Library/Application Support/Amethyst/Layouts/centered-twin-columns.js
Files are tracked in the FILES array within the script and can be easily modified.
Edit the FILES array in the dot-sync script:
FILES=(
".vimrc"
".bashrc"
".git-completion.bash"
".inputrc"
"custom-config.conf"
# ... add more files here
)For files where the repo path differs from the local path, use the => syntax:
FILES=(
".vimrc" # Implicit: ~/.vimrc <=> ./vimrc (basename)
"Library/Application Support/Amethyst/Layouts/centered-primary-columns.js => centered-primary-columns.js"
)- Left side: Path relative to
$HOME - Right side: Path relative to the repository root
- If no
=>is specified, the repo path defaults to the basename of the local path
DOTSYNC_REPO: Override the repository directory (defaults to the script's directory)export DOTSYNC_REPO="/path/to/custom/repo"
dot-sync supports host-scoped .bashrc extensions committed in this repo.
- Naming convention:
.local/bashrc.$HOSTNAME_SHORT.sh - Load behavior:
.bashrcsources only the host-specific file for the current machine. - Host key source:
hostname -s
Setup:
cd ~/code/dot-sync
mkdir -p .local
cp .local/bashrc.HOSTNAME.example.sh ".local/bashrc.$(hostname -s).sh"
$EDITOR ".local/bashrc.$(hostname -s).sh"Example use case for PostgreSQL build tooling on one machine:
pathappend "/opt/homebrew/opt/libpq/bin"
export LDFLAGS="-L/opt/homebrew/opt/openssl@3/lib -L/opt/homebrew/opt/libpq/lib ${LDFLAGS:-}"
export CPPFLAGS="-I/opt/homebrew/opt/openssl@3/include -I/opt/homebrew/opt/libpq/include ${CPPFLAGS:-}"
export PKG_CONFIG_PATH="/opt/homebrew/opt/openssl@3/lib/pkgconfig:/opt/homebrew/opt/libpq/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"Commit the created host file if you want this machine's augmentation tracked in repo history.
All modified files are automatically backed up before being overwritten.
- Backup location:
.bak/<filename>/bak.YYYY-MMDD-HHMMSS - Format: Timestamped with
YYYY-MMDD-HHMMSS(e.g.,2025-11-06-143022) - Retention: Backups are kept indefinitely; clean up manually if needed
Example:
.bak/
├── .bashrc/
│ ├── bak.2025-11-01-091500
│ ├── bak.2025-11-05-143022
│ └── bak.2025-11-06-102033
└── .vimrc/
└── bak.2025-11-02-164512
The .bak/ directory is excluded from version control via .gitignore.
This repository includes several useful Git and file utilities that are synced to ~/.local/bin:
Generate AI-powered commit messages using the llm CLI tool.
Features:
- Analyzes
git diff --cachedto understand staged changes - Generates commit messages following best practices:
- Subject line ≤ 50 characters
- Optional body wrapped at 72 characters
- Proper capitalization and formatting
- Opens the generated message in your editor for review
Usage:
git add .
git-ai-commitDependencies:
llmCLI tool- OpenAI API key configured (
llm keys set openai)
Clean up local Git branches based on their upstream status.
Behavior:
- Merged branches (upstream exists): Pull latest, then delete with
git branch -d - Deleted upstream (upstream gone): Force delete with
git branch -D - No upstream: Keep the branch (preserves local work)
- Current branch: Never deleted (automatically skipped)
- Protected branches:
mainandmasterare always preserved
Usage:
git-clean-local-branchesInteractive tool for cleaning up and squashing commits before merging.
Usage:
git-clean-rebaseBulk converter for HEIC images to JPEG format (useful for iOS photo exports).
Usage:
convert-heics-to-jpgs /path/to/photos/AI-powered file organizer that intelligently categorizes and moves files into your Documents directory.
Features:
- Analyzes Documents directory structure using
tree - Reads file names and contents (when possible)
- Uses AI to determine the best destination folder
- Suggests improved filenames following naming conventions
- Supports dry-run mode to preview changes
- Creates directories as needed
- Prompts before overwriting existing files
Usage:
# Preview what would happen (safe)
organize-files --dry-run somefile.pdf
# Organize one or more files
organize-files file1.pdf file2.docx
# Organize multiple files at once
organize-files ~/Downloads/*.pdf
# Use custom Documents directory
organize-files --documents /path/to/docs file.pdfDependencies:
treecommandllmCLI tool- OpenAI API key configured (
llm keys set openai)
Naming Convention: The tool follows a consistent naming pattern:
- Lowercase letters
- Hyphens to separate words
- Dates in YYYY-MMDD format
- Descriptive, semantic names
Examples:
# A receipt file gets organized into finance/receipts
organize-files receipt-from-restaurant.pdf
# -> ~/Documents/finance/receipts/receipt-2024-12-15.pdf
# A wedding document goes to the wedding folder
organize-files --dry-run table-layout.pdf
# -> Preview: ~/Documents/wedding/wedding-table-layout.pdfContributions are welcome!
- Fork the repository
- Create a feature branch (
git checkout -b feat/your-feature) - Make your changes and test thoroughly
- Commit using descriptive messages
- Submit a pull request with a clear description and rationale
Distributed under the MIT License. See LICENSE for details.