プログラミング
Show HN: DriveSync – 高速なGit風Googleドライブ同期CLI
Show HN: DriveSync – fast Git-styled Google Drive sync CLI (github.com)
要約
DriveSync (dsync) は、ローカルフォルダとGoogleドライブフォルダを同期する、Rust製の高速なコマンドラインツールです。Gitにインスパイアされた設計で、ローカルの変更をプッシュしたり、リモートの変更をプルしたり、差分を確認したりできます。インストールはHomebrewやバイナリ、ソースから可能で、セットアップもOAuthクライアントIDの作成と初期化コマンドで容易に行えます。
全文翻訳
DriveSync (dsync)
ローカルフォルダとGoogleドライブフォルダを同期する、小さく高速なコマンドラインツールです。ローカルの変更をプッシュし、リモートの変更をプルし、あるいは単に何が違うかを確認できます。
Rustで書かれており、odeke-em/driveに倣っています。
ホーム: https://scaleninja.com/drivesync/
ソース: https://github.com/scaleninja/drivesync
ライセンス: MIT
dsync init ~/gdrive --remote-folder backups/lab --credentials ~/Downloads/client_secret.json
cd ~/gdrive
dsync diff # 何が違うか?
dsync push # ローカルの変更をアップロード(計画を表示し、最初に確認を求めます)
dsync pull # リモートの変更をダウンロード
インストール
Homebrew (macOSおよびLinux):
brew install scaleninja/tap/drivesync
これによりscaleninja/tapが追加されるため、他のscaleninjaツールは通常のbrew install <name>でインストールできます。(Homebrewが「信頼されていないタップ」エラーで拒否する場合、まずbrew trust scaleninja/tapを実行してください。)
または、LinuxまたはmacOS(x86_64およびarm64)用のプリビルドバイナリをリリースページから入手してください:
case "$(uname -s)-$(uname -m)" in Linux-x86_64) asset=linux-x86_64 ;; Linux-aarch64) asset=linux-arm64 ;; Darwin-x86_64) asset=macos-x86_64 ;; Darwin-arm64) asset=macos-arm64 ;; *) echo "unsupported platform"; exit 1 ;; esac
curl -fL -o /tmp/dsync "https://github.com/scaleninja/drivesync/releases/latest/download/dsync-$asset" \ && chmod 755 /tmp/dsync && sudo mv /tmp/dsync /usr/local/bin/dsync
または、Rustツールチェーンを使用してソースから:
git clone https://github.com/scaleninja/drivesync && cd drivesync && make install.
セットアップ
dsyncは、作成したOAuthクライアントを使用してDriveと通信します。そのため、バイナリに認証情報は埋め込まれていません。
Google Cloud Consoleでの一度限りの手順(スクリーンショット付きのステップバイステップのウォークスルーがあります):
プロジェクトを作成(または選択)します。
APIs & Services → Library: Google Drive APIを有効にします。
APIs & Services → OAuth consent screen: Externalを選択し、アプリに名前を付けます(この名前は同意ページに表示されます)。サポートメールを入力し、Test usersに自分を追加します。
APIs & Services → Credentials → Create Credentials → OAuth client ID: Desktop appを選択し、JSONをダウンロードします。
その後、フォルダを初期化します。
ブラウザが開いて同意を求められます。ツールはループバックポートでコードを受け取り、トークンをフォルダ内の.gd/に保存します(モード0600、アップロードされません)。
dsync init ~/gdrive --remote-folder backups/lab --credentials ~/Downloads/client_secret.json
Googleは、テスト中のExternalアプリの更新トークンを7日間で期限切れにします。毎週initを再実行するように求められた場合は、同意画面でアプリを公開をクリックしてください(個人使用には検証は不要です)。
使用方法
同期フォルダ内のどこからでも任意のコマンドを実行します。
PATHは現在のディレクトリからの相対パスであり、ファイルまたはフォルダを指定できます。デフォルトは.です。
コマンド
init [DIR] --remote-folder P --credentials F
DIRを、My Drive/Pをミラーリングする同期フォルダとして承認し、設定します。
--depth N はレベルを制限します(-1 = 無制限)。
push [PATH]
ローカルで新規または更新されたファイルをアップロードします。計画を表示し、最初に確認を求めます。
pull [PATH]
Driveで新規または更新されたファイルをダウンロードします。計画を表示し、最初に確認を求めます。
diff [PATH]
変更されたものをリスト表示します。変更がない場合は終了ステータス0、差分が見つかった場合は1、エラーまたは転送失敗の場合は2を返します。
status
ローカルフォルダ、リモートフォルダ、深度、キャッシュ状態、無視ファイル、ファイルシステムの種類、トークン有効期限を表示します。
update-cache
リモートツリーのインデックスを更新します。
version
バージョンを表示します。
push、pull、diffのオプション:
オプション | 効果
-y, --no-prompt | 確認なしで適用します。計画に競合が含まれる場合は拒否されます。
--force | 宛先が新しいか、同じmtimeで内容が異なる場合でも上書きします。ケースの衝突は決して強制されません。
-j N, --threads N | 並列ストリーム(デフォルト8、最大64)。
--refresh | キャッシュされたインデックスを無視し、リモートツリー全体を再リストします。
--fast | rsyncスタイルのクイックチェック:サイズとmtimeが同じであれば、ファイルを読み込まずに信頼します。
--verify | ローカルハッシュキャッシュを信頼する代わりに、ハッシュが必要なすべてのファイルを再読み込みします。
同期ルートの.driveignoreにgit-ignoreスタイルのパターンを配置して、除外します(initは.DS_Storeと._*を含むものを生成します)。
.gd/、シンボリックリンク、および非正規ファイルは同期されません。
終了ステータスは、成功の場合は0、差分が見つかった場合は1、エラーまたは転送失敗の場合は2です。
PATHはディスク上のスペルで指定されるため、macOSでpush Docsとpush docsは同じフォルダを意味します。
ワークスペースでは一度に1つのdsyncコマンドのみが実行され、2番目のコマンドは待機します。
変更をどのように決定するか
各サイドは、サイズ、mtime、およびMD5のパスセットです。DriveはサーバーサイドでMD5を計算し、リストに含めて返すため、リモートサイドはフリーです。
ファイルは最も安価なチェックから比較されます。
異なるサイズ → 異なる、何も読み込まれません。
それ以外の場合、ローカルMD5が比較されます。これは一度計算され、ファイルのサイズとmtimeに対してキャッシュされるため、最初の実行後、statが変更されたファイルのみが再度読み込まれます(--verifyはキャッシュをバイパスし、--fastはサイズとmtimeが一致する場合にハッシュをスキップします)。
等しいMD5 → 同一、mtimeに関係なく。
異なるMD5 → 新しい方が勝ちます(1秒の許容範囲)。
同じmtimeで内容が異なる場合は競合です。
転送後、両方のサイドは同じmtimeを持つため、diffは何も変更されるまで何も報告しません。
リモートツリーは一度完全にインデックス化され、その後Drive Changes APIを通じて最新の状態に保たれるため、繰り返し実行してもDriveのリストは再取得されません。
Pushとpullは、変更ごとに1行を表示し、実行前に確認を求めます:
+ photos/2026/
+ photos/2026/a.jpg 1,234,567 B
M docs/report.txt 12,340 B, ローカルが新しい
! docs/Budget はスキップされました: リモートはGoogleネイティブドキュメントです。上書きされません
C notes.txt 競合: リモートが新しい
追加 2 件
ソース: 1,234,567 B
変更 1 件
ソース: 12,340 B
変更を続行しますか? [Y/n]:
+ 作成 · M 上書き · ! 構造上の理由でスキップ · C 競合 · E 読み取り不能なローカルファイル。
決して行わないこと
どちらのサイドでも、何も削除しません。ローカルで削除されたファイルはDriveに残ります。逆も同様です。
--forceなしで競合を上書きしたり、ファイルシステムがそれらを折りたたむ場合の名前の衝突(大文字小文字またはUnicode正規化)を上書きしたりしません。
競合が存在する場合、プロンプトはデフォルトでnoになり、--no-promptは実行を拒否し、入力終了は決してyesと見なされません。
古いデータを書き込みません。書き込み直前に各宛先が再チェックされます。ローカルファイルは、計画が認識したサイズとmtimeをまだ持っている必要があります。Driveファイルは、計画が認識したMD5、mtime、名前、および親フォルダをまだ持っている必要があります。作成されるファイルはまだ存在しない必要があります。新しいコンテンツが入るすべてのフォルダは、インデックスが同期ツリー内に配置した場所にまだ存在する必要があります。それらの間に変更があった場合は報告され、そのままにされます。
読み取り中またはアップロード中に変更されたローカルファイルはエラーとして報告され、すべてのアップロードはDriveが計算したMD5に対して検証されます。
同期フォルダをエスケープします。シンボリックリンク、.gd/内、無視されたパス、または非正規ファイルには何も書き込まれません。
ダウンロードはプライベート一時ファイルに行われ、DriveのMD5に対して検証された後、既存のパーミッションを維持してリネームされます。
重複を作成しません。Driveは、作成の直前に同じ名前のエントリを要求し、作成はDriveによって事前に生成されたIDを使用するため、応答の喪失後のリトライや古いインデックスでも、2番目のコピーを作成したり、誰かのファイルを採用したりしません。Driveがすでに重複を保持している場合、最も古いものが一貫してパスを所有します。
5MBを超えるファイルは、再開可能なアップロードを通じてストリーミングされます。レート制限、ネットワークエラー、および停止した接続はバックオフ付きで再試行されます。Ctrl-Cで中断されたプッシュまたはプルは、単純に再実行できます。
リモートフォルダがDriveでゴミ箱に入れられたり削除されたりすると、すべてのコマンドが停止してその旨が表示されます。
破損した.gd/cache.dbは自動的に再構築されます。これは単なるインデックスです。
既知の制限事項
同じDriveフォルダを同期する2台のマシンは調整されません。3方向マージはありません。
Drive APIには条件付き更新がないため、リモートファイルが計画が認識したものであることを確認するチェックと、