Google Drive Remote

The Google Drive remote lets you export annexed data to a Drive folder where collaborators can browse, download, and share files using the Drive UI — without needing S3 access or the exo CLI.

What It Does

An exo Drive remote exports your git-annexed files to a Google Drive folder, preserving the working tree layout as Drive folder hierarchy. For example:

data/results/sample_001.parquet  →  Drive: my-drive/results/sample_001.parquet
data/results/sample_002.parquet  →  Drive: my-drive/results/sample_002.parquet

Collaborators see real filenames and a familiar folder structure in the Drive UI. They can share, preview, and download files as normal Drive items.

Drive remotes are export-only in v1. You cannot import data from Drive into git-annex with this remote type.

Configuration

Add a Drive remote to .exohub/remotes:

remotes:
  - name: my-drive
    type: drive
    drive_path: /My Drive/datasets/gwasdb
    tracking_branch: main
    include:
      - gwasdb-studies/**/*.parquet
FieldRequiredDescription
nameYesRemote name; used with --with and --to flags
typeYesMust be drive
drive_pathYesFull Drive path to the target folder (see constraints )
tracking_branchNoBranch to track for preferred content
includeNoGlob patterns — only matching files are exported
excludeNoGlob patterns — matching files are skipped

Run exo init after editing .exohub/remotes to configure the remote.

Alternatively, use exo init remote to set up the remote interactively or declaratively without editing the file manually:

# Interactive TUI — prompts for name, drive_path, and tracking branch
exo init remote --type drive

# Declarative — provide values directly
exo init remote --type drive --name my-drive

The git-annex-remote-drive helper binary is installed automatically alongside exo by the standard install script.

Authentication

Google Drive access requires OAuth2 authorization. Authorization is a separate step from syncing — run it once per machine using the exo auth command.

Device Flow

exo auth always uses Google’s device flow (TV/Limited Input), which works in any environment — interactive terminals, remote servers, or CI runners — without requiring a browser on the same machine:

exo auth my-drive
To authorize exo to access Google Drive:
  1. Go to: https://www.google.com/device
  2. Enter code: ABCD-EFGH

Waiting for authorization... ✅

✅ Authorized. Token saved to ~/.config/exo/drive-tokens/my-drive.json
   You can now run: exo sync --with my-drive

Open the URL on any device (phone, laptop, etc.), enter the code, and grant access. The CLI polls until consent is complete.

To re-authorize a remote that is already authorized (e.g., to switch accounts), use --force:

exo auth --force my-drive

Note: exo sync --with <remote> fails immediately if no token exists for the remote. It does not trigger authorization inline. Always run exo auth <remote-name> first.

Token Storage and Renewal

Tokens are stored in ~/.config/exo/drive-tokens/<remote-name>.json (file permissions 0600). Subsequent syncs are fully automatic — the CLI refreshes the access token using the stored refresh token without prompting again.

If the refresh token is revoked (e.g., you disconnected the app in your Google account settings), exo automatically re-triggers the consent flow the next time you sync:

You do not need to run exo auth again manually — just re-run exo sync --with <remote-name> and follow the prompt.

Using the Remote

Sync (upload + export)

exo sync --with my-drive

This exports files matching the remote’s preferred content rules (from include/exclude) to Drive.

Export to Drive

exo export --to my-drive

Exports all tracked files to the Drive folder with their original directory layout.

Export specific paths

exo export --to my-drive --path data/processed/

Export a specific version

exo export --to my-drive --ref v1.0.0

drive.file Scope

The exo Drive remote uses the drive.file OAuth2 scope only. This means:

This is a permanent constraint — there is no configuration option to grant broader Drive access.

drive_path Constraints

The drive_path in your .exohub/remotes configuration specifies the target folder path in Drive.

The folder must not already exist before the first sync. Because exo uses the drive.file scope, it can only see folders it created itself. If you point drive_path at a pre-existing folder, exo cannot locate it and will create a new folder with the same name alongside it — leading to duplicate folders and confusion.

Choose a path that does not yet exist, and exo will create the full folder hierarchy on first sync:

# ✅ Good: folder does not exist yet — exo will create it
drive_path: /My Drive/datasets/gwasdb-2024

# ❌ Bad: folder already exists and was not created by exo
drive_path: /My Drive/datasets/shared-folder

Due to the drive.file scope, the app can only access folders it created. This constraint is intentional — it ensures exo can never read or modify files unrelated to the dataset.

include / exclude Patterns

Patterns in .exohub/remotes are enforced at the remote binary level, not just via git-annex preferred content. This means both plain git files (like .exohub/ metadata) and annexed files respect the patterns.

Patterns use glob syntax:

Large Files

Files larger than 5 MB are uploaded using Google’s resumable upload protocol automatically. This is transparent — no configuration is needed. Resumable uploads are more reliable over unstable connections because each chunk is retried independently.

For smaller files (under 5 MB), exo uses a single-part multipart upload.

Limitations

LimitationDetails
Export only (no import)Files can be pushed to Drive but not pulled back in v1
No Shared DrivesGoogle Workspace Shared Drives (Team Drives) are not supported in v1; use a personal My Drive folder
Drive API rate limits12,000 requests per 100 seconds; large exports with many small files may be throttled — exo retries automatically with backoff
Files are permanently deletedexo deletes exported files via the Drive API (REMOVEEXPORT); deleted files do not go to Drive Trash

OAuth2 Client Credentials

The exo binary includes a built-in Google OAuth2 client ID for the drive.file scope. This is a Desktop/TV application credential — the same pattern used by tools like gcloud, rclone, and gh.

Security note: For Desktop/TV OAuth2 clients, the client secret embedded in the binary is not a true secret. It allows initiating an OAuth2 flow, but access always requires explicit user consent. Combined with drive.file scope, even a leaked credential can only access files created by the app.

All exo users share the same Google Cloud project quota (12,000 queries/100s). For teams with high-volume exports, you can supply your own credentials via environment variables:

export GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
export GOOGLE_CLIENT_SECRET=your-client-secret
exo sync --with my-drive

Complete Workflow Example

# 1. Add Drive remote to .exohub/remotes (see Configuration above)

# 2. Initialize
exo init
# ⚠️  Drive remote 'my-drive' needs authorization. Run: exo auth my-drive

# 3. Authorize (one-time, per machine)
exo auth my-drive
# Follow device flow: visit https://www.google.com/device, enter code

# 4. Sync
exo sync --with my-drive

# 5. Check what was exported
exo locate data/

# 6. Subsequent syncs are automatic (token refreshed silently)
exo sync --with my-drive

For Collaborators

When someone clones a repository that has a Drive remote configured:

  1. Clone and initialize as usual:

    exo clone <repo-url>
    cd <repo>
    exo init
    # ⚠️  Drive remote 'my-drive' needs authorization. Run: exo auth my-drive
    
  2. Run exo auth to authorize their own Google account:

    exo auth my-drive
    
  3. Sync normally:

    exo sync --with my-drive
    

Each user authorizes independently using their own Google account. Tokens are stored per-machine in ~/.config/exo/drive-tokens/ and are never committed to the repository.

Next Steps