A bidirectional file synchronization tool for syncing local directories with Google Drive.
- Bidirectional Sync: Automatically syncs changes between local directories and Google Drive
- Real-time Monitoring: Detects local file changes instantly using fsnotify
- Remote Polling: Polls Google Drive for remote changes at configurable intervals
- Conflict Resolution: Multiple strategies (last_write_wins, local_wins, remote_wins, keep_both)
- Deletion Policies: Configurable deletion propagation (bidirectional, one-way, or none)
- Ignore Patterns: Support for .syncignore files and YAML-based patterns
- Per-Directory Configuration: Override global settings for each sync target
- SQLite State Tracking: Efficient change detection with local database
- Graceful Shutdown: Completes in-flight operations before exiting
- Go 1.26 or later
- Google Drive API credentials (OAuth 2.0)
- macOS, Linux, or Windows
git clone https://github.com/rschone/filesync.git
cd filesync
make buildThe binary will be created at ./bin/filesync.
sudo cp bin/filesync /usr/local/bin/- Go to Google Cloud Console
- Create a new project (or select existing)
- Enable the Google Drive API
- Create OAuth 2.0 credentials (Desktop app)
- Download the credentials JSON
- Extract
client_idandclient_secret
You'll need to obtain OAuth tokens. You can use the Google OAuth Playground:
- Go to https://developers.google.com/oauthplayground/
- Click the gear icon (⚙️) in top right
- Check "Use your own OAuth credentials"
- Enter your Client ID and Client Secret
- In "Step 1", select "Drive API v3" → "https://www.googleapis.com/auth/drive"
- Click "Authorize APIs"
- Authorize the application
- In "Step 2", click "Exchange authorization code for tokens"
- Copy the
access_token,refresh_token, andexpires_in
Create a configuration file at ~/.filesync/config.yaml:
mkdir -p ~/.filesync
cp config.yaml.example ~/.filesync/config.yamlEdit the configuration file with your credentials and paths. See Configuration Example below.
filesync --config ~/.filesync/config.yaml --log-level info--config- Path to configuration file (default:~/.filesync/config.yaml)--log-level- Log level: debug, info, warn, error (default:info)
Press Ctrl+C to gracefully stop synchronization. The application will complete any in-flight operations before exiting.
version: "1.0"
# Global default settings
global:
sync_delay: 2s # Debounce delay for local changes
remote_poll_interval: 60s # How often to check Google Drive for changes
conflict_resolution: last_write_wins # Default conflict strategy
deletion_policy: propagate_both # Default deletion policy
initial_sync: merge # Default initial sync mode
workers: 4 # Number of concurrent sync workers
retry_attempts: 3 # Number of retries for failed operations
retry_backoff: 1s # Base delay for exponential backoff
database_path: ~/.filesync/sync.db # SQLite database location
# Global ignore patterns (applied to all targets)
ignore_patterns:
- "*.tmp"
- ".DS_Store"
- "Thumbs.db"
- ".git/"
- "node_modules/"
# Sync targets
targets:
- id: documents # Unique identifier
local_path: ~/Documents/Work # Local directory to sync
remote_path: /Work # Google Drive folder path
provider: gdrive # Cloud provider (currently only gdrive)
enabled: true # Enable this target
# Google Drive OAuth2 credentials
credentials:
oauth2:
client_id: "YOUR_CLIENT_ID.apps.googleusercontent.com"
client_secret: "YOUR_CLIENT_SECRET"
access_token: "ya29.a0..."
refresh_token: "1//0g..."
token_expiry: "2026-03-08T12:00:00Z"
# Optional: Override global settings for this target
sync_delay: 5s
conflict_resolution: keep_both
ignore_patterns:
- "*.draft"
- "temp/"| Option | Type | Default | Description |
|---|---|---|---|
sync_delay |
duration | 2s | Debounce delay for batching rapid local changes |
remote_poll_interval |
duration | 60s | How often to poll Google Drive for changes |
conflict_resolution |
string | last_write_wins | Default conflict resolution strategy |
deletion_policy |
string | propagate_both | Default deletion propagation policy |
initial_sync |
string | merge | Default initial synchronization mode |
workers |
int | 4 | Number of concurrent sync operations |
retry_attempts |
int | 3 | Number of retry attempts for failed operations |
retry_backoff |
duration | 1s | Base delay for exponential backoff retries |
database_path |
string | ~/.filesync/sync.db | SQLite database file location |
ignore_patterns |
[]string | - | Global file ignore patterns |
last_write_wins- File with newer modification time winslocal_wins- Local changes always take precedenceremote_wins- Remote changes always take precedencekeep_both- Keep both versions with conflict suffixes
propagate_both- Deletions sync bidirectionally (default)propagate_local- Only propagate local deletions to remotepropagate_remote- Only propagate remote deletions to localnone- Never propagate deletions
merge- Combine files from both local and remote (default)local_to_remote- Upload all local files to remoteremote_to_local- Download all remote files to local
Create a .syncignore file in any directory to exclude files from sync:
# .syncignore example
*.tmp
*.swp
.DS_Store
node_modules/
__pycache__/
*.pyc
*.tmp- Match files with .tmp extensionnode_modules/- Match directory and all contents**/test- Match "test" in any subdirectory!important.tmp- Negate pattern (not yet implemented)
Patterns are evaluated using glob matching with support for *, ?, [], and **.
Filesync uses SQLite to track file metadata and sync state. The database stores:
- File paths, sizes, modification times, and hashes
- Sync state (synced, pending, conflict, error)
- Last sync timestamps
- Remote file IDs for efficient lookups
- Sync operation logs
Database location is configurable via global.database_path.
make buildmake testmake checkmake clean- Verify your OAuth credentials are correct
- Check if the access token has expired (refresh token should auto-renew)
- Ensure the Google Drive API is enabled in your Google Cloud project
- Another filesync instance may be running
- Check for stale lock files in the database directory
- Restart the application
- Check the log output for errors (
--log-level debug) - Verify the file doesn't match ignore patterns
- Check if the file is being debounced (rapid changes)
- Ensure you have write permissions
- Multiple sync operations tried to update the same file simultaneously
- The operation will be retried automatically
- If persistent, check for concurrent filesync instances
filesync/
├── cmd/filesync/ # Main application
├── internal/
│ ├── config/ # Configuration loading and validation
│ ├── storage/ # SQLite database interface
│ ├── provider/ # Cloud provider implementations
│ │ └── gdrive/ # Google Drive client
│ ├── watcher/ # File system watchers
│ ├── syncer/ # Sync engine and orchestration
│ ├── models/ # Data models
│ └── hash/ # File hashing utilities
└── pkg/logger/ # Structured logging
Contributions are welcome! Please feel free to submit pull requests or open issues.
TBD
Built with:
- fsnotify - File system notifications
- Google Drive API - Cloud storage
- SQLite - Local database
- Zap - Structured logging