この記事は、Infocom Advent Calendar 2022 4日目の記事です。
PCをオフライン環境で使いたいときには必要なファイルをコピーして持っていくことになり、作業中に何らかの更新が発生したら作業後はコピー元に戻しますね。
gitで管理すればいいものもあるしソースはそうしてますけど、パワポやExcelとかまあいろんな雑多なファイルをgitに全部入れるわけにもいきません。
とはいえ毎回手動でコピーして戻すとなるとミスもするし、毎回毎回手作業でやるのはうんざりするので自動化を考えました。
- シェルスクリプト/バッチファイルでコピーコマンドを使う
- 全部コピーするので単純に遅い
- 戻すのは手作業
- rsync
- 一方向しかできない
- 両方に修正があると詰む
- 結局、戻すのは手作業
- unison
- 両方の修正を検出してそれなりにいい感じにやってくれる。これだ!
unison
どうやら結構古くからあるUnix系のOSSツールのようです。
私は1995年頃からUnix系OSを使っているのですが知りませんでした。
LinuxやMacだけじゃなくWindows用のバイナリもあったのはうれしい。
コンフリクトを検出できる。
SSHでも同期できる。
rsyncのような部分転送になっているということでコピーが高速。ファイル数が多ければそれなりに時間はかかりますが、普段使いの感じだと十分早いなと思います。
お手軽。これだいじ。
- インストール
$ brew install unison Warning: Treating unison as a formula. For the cask, use homebrew/cask/unison 🍺 /usr/local/Cellar/unison/2.53.0: 9 files, 3.9MB
Windowsはscoopで入れてます。
> scoop install unison Installing 'unison' (2.53.0) [64bit] from main bucket unison-v2.53.0+ocaml-4.12.1+x86_64.windows.zip (29.8 MB) [====================================================] 100% Checking hash of unison-v2.53.0+ocaml-4.12.1+x86_64.windows.zip ... ok. Extracting unison-v2.53.0+ocaml-4.12.1+x86_64.windows.zip ... done. Linking ~\scoop\apps\unison\current => ~\scoop\apps\unison\2.53.0 Creating shim for 'unison'. Creating shim for 'unison-fsmonitor'. 'unison' (2.53.0) was installed successfully! Notes ----- Compiled with same OCaml compiler version 4.12.1
main bucketにあったのでbucket追加しなくても普通に入ると思います。
使ってみる
ということで使ってみます。
- コマンドで実行
unison root1 root2
で起動します。
$ tree foo bar foo ├── aaa │ └── hogehoge.pptx └── hoge.txt bar [error opening dir] $ unison foo bar Unison 2.52.1 (ocaml 4.12.0): Contacting server... Looking for changes Warning: No archive files were found for these roots, whose canonical names are: /Users/gozu/Documents/foo /Users/gozu/Documents/bar Reconciling changes foo bar dir ----> [f] Proceed with propagating updates? [] y Propagating updates [BGN] Copying from /Users/gozu/Documents/foo to /Users/gozu/Documents/bar [END] Copying $ tree foo bar foo ├── aaa │ └── hogehoge.pptx └── hoge.txt bar ├── aaa │ └── hogehoge.pptx └── hoge.txt
初回なのでまるっとコピーされました。
相手のディレクトリが無ければ単純に複製ができます。
bar/hoge.txt
を修正して、同期してみる
$ unison foo bar foo bar <---- new file .hoge.txt.un~ [f] <---- changed hoge.txt [f] <---- new file hoge.txt~ [f] Proceed with propagating updates? [] y Propagating updates [BGN] Copying .hoge.txt.un~ from /Users/gozu/Documents/bar to /Users/gozu/Documents/foo [END] Copying .hoge.txt.un~ [BGN] Updating file hoge.txt from /Users/gozu/Documents/bar to /Users/gozu/Documents/foo [END] Updating file hoge.txt [BGN] Copying hoge.txt~ from /Users/gozu/Documents/bar to /Users/gozu/Documents/foo [END] Copying hoge.txt~
barのファイルがfooへ同期されています。
が、vimの管理ファイルまで同期されてますね。これは設定で除外できます。
- 双方で同じファイルを更新してみる
$ unison foo bar foo bar changed <-?-> changed hoge.txt [] d diff -u '/Users/gozu/Documents/bar/hoge.txt' '/Users/gozu/Documents/foo/hoge.txt' --- /Users/gozu/Documents/bar/hoge.txt 2022-12-02 20:07:40.000000000 +0900 +++ /Users/gozu/Documents/foo/hoge.txt 2022-12-02 20:07:45.000000000 +0900 @@ -1,3 +1 @@ hello unison. -hello unison. -hello unison. changed <-?-> changed hoge.txt [] x foo : changed file modified on 2022-12-02 at 20:07:45 size 14 rw-r--r-- bar : changed file modified on 2022-12-02 at 20:07:40 size 42 rw-r--r-- changed ====> changed hoge.txt [] > Proceed with propagating updates? [] y Propagating updates [BGN] Updating file hoge.txt from /Users/gozu/Documents/foo to /Users/gozu/Documents/bar [END] Updating file hoge.txt
修正したファイルがテキストファイルなのでdiffを取ることができました。
あとはファイルの日付やサイズを確認したり。
どちらを採用するか >
で指定しています。
インタラクティブなコマンドは
このくらいでなんとかなるかな。
よく使う設定を定義できる
確かにいいんですが、これだとあんまり便利になってませんね。
いらないファイルを除外したり、新しいファイルを採用して欲しいし、いちいち指定せずとも全部自動でやって欲しい。
なので、設定ファイルを書いて自動実行できるようにします。
Macだと ~/.unison
ディレクトリを作って、拡張子がprfのファイルを作ります。
(Windowsでは C:\Users\アカウント名\.unison
です)
default.prf
は定義名を指定せずにunisonを実行したときに使われます。
unison 定義名
とすると ~/.unison/定義名.prf
が使われます。
私の設定ファイルは以下のようになっています。
includeで読み込むための基本的な設定(common.prf
)をしておくと、コピーする対象ごとに設定ファイルを作ることができ、最小の設定ファイルにできます。
$ cat ~/.unison/default.prf # Unison preferences file # https://88171.net/unison-manual-ja # https://www.seas.upenn.edu/~bcpierce/unison/download/releases/stable/unison-manual.html # 自動実行 batch = true # ownerも同期する owner = true # タイムスタンプをコピーする(ディレクトリはできない) times = true # permissionを設定しない perms = 0 # chmodしない perms=0と組み合わせる dontchmod = true # 新しいファイルを優先 prefer = newer # 新規作成ファイルはユーザに同期如何を問わない auto = true # ファイル更新日時による更新有無の判定(Windowsでは更新日時が変わらないことがあるのでたまにfalseにするとよいらしい) fastcheck = true # エラー以外の出力停止をしない silent = false # 無視するディレクトリやファイル名を指定する ignore = Name .DS_Store ignore = Name Icon? ignore = Name {.*.swp,*.*~} ignore = Name {*.gsheet,*.gslides,*.gdoc}
$ cat ~/.unison/foo.prf # Include the contents of the file common include common # 同期する対象のルートパスの定義 root = /Users/gozu/Documents/foo/ root = /Volumes/bar/foo/ # バックアップ backup = Name * maxbackups = 5 backupprefix = $VERSION. backupdir = /Volumes/nas/backup/unison/foo
実行は、 unison foo
と打つだけです。
こうして設定を分けておく事で、重要性に応じてバックアップの世代数や取るファイルの種類、ディレクトリを変えることができます。
設定のオプションやサンプルが色々載っているので、
https://www.seas.upenn.edu/~bcpierce/unison/download/releases/stable/unison-manual.html
を、見てやってます。DeepLを使うと驚くほどわかりやすく訳してくれます。
使い道
MacやWindows、NASなどプラットフォームを越えて個人的なディレクトリを同期するのにはとても便利です。
ファイルを消すときはやっぱり注意が必要。どっちを消しても消える事になるので、rsyncの--deleteオプションより危険な事もあると思う。
更新する人が不特定多数なところで使うのちょっと躊躇しますね。
でも、ログやバックアップがいい感じに取れるので運用次第で使えるのかも?
双方向で同期出来て普通のコピーより早いし差分更新でマルチプラットフォームとなればもっと使われてもいいのになーと思ってこのブログを書きながら何となくググっていたらdocker-syncというツールで使われているというのが分かった。コンテナの中のファイルとホスト側のファイルを同期させるもののようです。
なるほど。いかにもなユースケースですね。