Open2

Git-LFSに格納した写真を整理したい(列挙)

okuokuokuoku

おでかけの度にAndroidに撮りためた写真は rsync でLinuxにコピーしてそこからGit-LFSにつっこんでいる。いやまぁOneDriveにも同期してるからアルバム的な機能はそちらでも良いけど、 たまに写真が脱落するケースがある のでできれば自前のソリューションを作りこんでおきたい。

https://zenn.dev/okuoku/scraps/225aca10c15a84

写真を格納したGit-LFSリポジトリのレイアウト

実はレイアウトは固定していない。

ルートには filelist.txt が置かれていて、これにはファイルの更新日付とリポジトリ内のパスが列挙されている。

1665635096.2769160390 sync/DCIM/Camera/PXL_20221013_042451921.jpg
1665635162.3969226260 sync/DCIM/Camera/PXL_20221013_042558573.jpg
1665635546.8669609270 sync/DCIM/Camera/PXL_20221013_043222958.jpg
1665636350.2937076320 sync/DCIM/Camera/PXL_20221013_044546545.jpg
1665637047.2437770620 sync/DCIM/Camera/PXL_20221013_045723860.jpg
1665637117.4304507210 sync/DCIM/Camera/PXL_20221013_045833592.jpg

そもそも Gitにはファイル単位の更新日付を記録する機能が無い ので苦肉の策でこうなっている。。写真にはExifメタデータとして撮影日時が入っているので必ず必要なわけでも無いし OneDriveも日付までは正確にバックアップしてくれない (秒以下切り捨て) のでそこまで重要なデータでも無いが。。

列挙の難しさ

... Android側や写真をバックアップしているLinuxマシン側の容量を節約するため、 ファイルを定期的に削除している 。このため、全ての写真を列挙するためには全てのコミットを処理する必要がある。

Git-LFSのLFSストレージはNASに置いているので、容量は事実上無限にある。ただ、Android側やLinux側に無い写真を探すためには、Gitリポジトリのそれらしいコミットをチェックアウトしてくる必要があって、それがちょっと面倒な感じになっている。

okuokuokuoku

bare repositoryからGit-LFSのoidを抽出する

ブランチの列挙

今回はLFSリポジトリを --mirror 付きでcloneし、 git show-ref で全ブランチを直接列挙することにした。mirrorによるcloneは自動的にbare repositoryになるので都合が良い。

$ git show-ref
c18355cf9c634ff1e24186d102b76f0dd3481a86 refs/heads/OneDrive
06574741b72beca69540ce1e28e597a16836433d refs/heads/master

ファイルリストを元にした列挙

git cat-file を駆使してファイルを単体抽出できる。Bareリポジトリを使うことで、Git-LFSのポインタファイルを確実に取り出すことが可能になる(Git-LFSはbareリポジトリをサポートしていないため)。

  1. git cat-file -p 61b7feb6ea40351c10e9aad7b10259fa59ebcec4:filelist.txt のようにして、ファイルリストを取り出す
  2. (既知のファイルで、かつ時刻が変わっていないものはスキップする)
  3. git cat-file -s 61b7feb6ea40351c10e9aad7b10259fa59ebcec4:sync/Movies/screen-20221015-181944.mp4 のようにして、ファイルサイズが1024バイト以下であることを確認する (LFSのポインタファイルであることの確認)
  4. git cat-file -p 61b7feb6ea40351c10e9aad7b10259fa59ebcec4:sync/Movies/screen-20221015-181944.mp4 のようにしてLFSのポインタファイルを取り出す
  5. LFSポインタファイルから oid を抽出する

写真ファイルは原則的にLFSで格納することにしている。このため、列挙されているファイルがLFSのファイルでない場合は安全にエラーにしたい。 ...ファイルをLFSにし損ねた場合、超巨大なファイルを git cat-file -p で読み込むことになるため、それを事前に防ぐほうが良いと判断した。

LFSのポインタファイルは以下のような内容のテキストファイルになっている。Git-LFSは、通常であれば、このようなファイルをsmudgeフィルタに掛けることで元のファイルに置き換えている。

$ git cat-file -p 61b7feb6ea40351c10e9aad7b10259fa59ebcec4:sync/Movies/screen-20221015-181944.mp4
version https://git-lfs.github.com/spec/v1
oid sha256:6355c5d3d45b717e15efff736b0a94afa3ff2ed730bca8dd35b9223e11a3532c
size 78514216

この場合 oid は 6355c5d3d45b717e15efff736b0a94afa3ff2ed730bca8dd35b9223e11a3532c で、これはファイルのSHA256そのものになる。