Skip to content

randylowe/google-driveless

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

google-driveless

A lightweight shell script for syncing Google Drive on macOS — without running the official app.

Early project. This script has been tested on a small Google Drive instance and is still evolving. Use at your own risk — I take no responsibility for data loss or any issues that arise. Keep backups of important files before running any sync tool.

Why

Google Drive for Desktop is memory hungry, installs kernel extensions, and runs multiple background processes you didn't ask for. If you have multiple Google accounts, multiply that cost.

This script replaces it. It uses rclone to bidirectionally sync your local folders with Google Drive — watching for local changes with fswatch and polling Drive for remote changes. No background app, no menu bar icon, no kernel extensions. Around 5 MB when active, nothing when idle.

Each Google account is a profile in a YAML config file with its own local folder, remote, and optional settings overrides.


Requirements

macOS only. Linux support is not yet implemented.

The script auto-installs missing dependencies via Homebrew on first run:

  • rclone — does the actual syncing
  • yq — reads the YAML config
  • fswatch — watches the local folder for changes (watch mode only)

Setup

1. Clone the repo

git clone https://github.com/yourname/google-driveless.git
cd google-driveless
chmod +x google-driveless.sh

2. Authenticate rclone with Google Drive

Run this once per Google account. Give each remote a memorable name (e.g. work-google, personal-google).

rclone config

Follow the interactive prompts: choose Google Drive, complete the browser OAuth flow. See the rclone Google Drive setup guide for full details including OAuth client configuration. When done, verify it works:

rclone ls work-google:

3. Configure your profiles

Copy the example config and edit it:

cp google-driveless.yaml.example google-driveless.yaml   # or edit google-driveless.yaml directly

At minimum, set local and remote for each profile:

profiles:
  - name: work
    local: ~/Work
    remote: work-google:Work

4. Run a dry-run to verify

./google-driveless.sh --dry-run

This previews what would sync without changing anything.

On the very first sync, the script automatically detects that no baseline exists and runs an initial resync to establish one. You don't need to do anything special.


Usage

# Sync all profiles once
./google-driveless.sh

# Sync a specific profile
./google-driveless.sh --profile work

# Preview changes without syncing
./google-driveless.sh --dry-run

# Watch all profiles continuously (local changes + remote polling)
./google-driveless.sh --watch

# Watch a single profile
./google-driveless.sh --watch --profile personal

# Force a full resync (useful after a long offline period)
./google-driveless.sh --init --profile work

# List configured profiles
./google-driveless.sh --list

# Use an alternate config file
./google-driveless.sh --config ~/my-other-google-driveless.yaml

In watch mode, local changes trigger a sync after a configurable debounce window (default 10s). Remote changes are detected by polling Drive on an interval (default 60s). Multiple profiles run as parallel watchers. Press Ctrl+C to stop all.


Configuration

All settings live in google-driveless.yaml. Profile values override defaults; CLI flags override everything.

defaults:
  # Performance
  transfers: 2              # parallel file transfers
  checkers: 4               # parallel file checks
  bwlimit: "10M"            # bandwidth cap (e.g. 10M, 1G, off)
  retries: 10
  tpslimit: "4"             # Google API transactions/sec

  # Behavior
  skip_gdocs: true          # skip Google Docs/Sheets/Slides (can't be downloaded as-is)
  resilient: true           # continue on non-fatal errors
  show_progress: true
  verbose: true

  # Conflict resolution
  conflict_resolve: "newer" # keep the newer file on conflict
  conflict_loser: "delete"  # delete the losing version
  conflict_suffix: "backup" # suffix added to conflict losers before deletion

  # Watch mode
  debounce: 10              # seconds to wait after last local change before syncing
  poll_interval: 60         # seconds between remote polls

profiles:
  - name: work
    local: ~/Work
    remote: work-google:Work

  - name: personal
    local: ~/Personal
    remote: personal-google:Personal
    bwlimit: "5M"               # override default for this profile

Ignoring files

Filter patterns live directly in google-driveless.yaml — no separate file needed.

Patterns under defaults.filters apply to every profile. Patterns under a profile's filters are merged on top for that profile only:

defaults:
  filters:
    - "- .DS_Store"       # applied to all profiles

profiles:
  - name: work
    local: ~/Work
    remote: work-google:Work
    filters:              # optional: additional exclusions for this profile
      - "- *.tmp"
      - "- node_modules/**"

See rclone filter docs for the full pattern syntax.


Running on startup (launchd)

To have watch mode start automatically at login, create a launchd plist.

Save this to ~/Library/LaunchAgents/com.yourname.google-driveless.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.yourname.google-driveless</string>
  <key>ProgramArguments</key>
  <array>
    <string>/bin/bash</string>
    <string>/path/to/google-driveless.sh</string>
    <string>--watch</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
  <key>KeepAlive</key>
  <true/>
  <key>StandardOutPath</key>
  <string>/tmp/gdrive-sync.log</string>
  <key>StandardErrorPath</key>
  <string>/tmp/gdrive-sync.log</string>
</dict>
</plist>

Then load it:

launchctl load ~/Library/LaunchAgents/com.yourname.google-driveless.plist

To stop it:

launchctl unload ~/Library/LaunchAgents/com.yourname.google-driveless.plist

Logs are written to /tmp/gdrive-sync.log.


Caveats

  • Google Docs, Sheets, Slides are skipped by default (skip_gdocs: true) because they can't be downloaded in their native format. Disable this if you want rclone to export them.
  • First sync is handled automatically — the script detects when no baseline exists and runs an initial resync before proceeding. You can also force a full resync at any time with --init.
  • This is not a real-time sync — local changes sync after the debounce window, remote changes sync after the poll interval.

Disclaimer

Use at your own risk. This script has been tested on a small Google Drive instance and is still evolving. I take no responsibility for data loss or any other issues that may arise from using it. Always keep backups of important files before running any sync tool.


License

MIT

About

Sync Google Drive on macOS without the memory-hungry official app

Topics

Resources

Stars

Watchers

Forks

Contributors

Languages