Open5

Git-LFSのファイルをいっこだけ手動DLする

okuokuokuoku

いやこれみんなどうやってんの。。無いと絶対困ると思うんだけど。。

今回はこういう感じに写真のバックアップをGit-LFSなGitリポジトリに取っている。このGit-LFSに格納した写真のメタデータを完全なチェックアウトなしで抽出していきたい。

okuokuokuoku

手順

とりあえず、

  1. git clone --no-checkout <REPOSITORY-URL>
  2. (LFSサーバに別途認証が必要な場合は、ここで認証する)
  3. git cat-file --filters HEAD:sync/DCIM/Camera/PXL_20220331_052024030.jpg | git lfs smudge > temp.jpg

とすることで抽出はできる。もうちょっと簡単なコマンドが有るかもしれない。

okuokuokuoku

cat-file --filters

通常のチェックアウトがある場合は、 git cat-file --filters によって直接ファイルを抽出できる。が、これは Git のsmudgeフィルタが裏で自動起動する必要があり、そのためには正当な内容のindexを持つ = チェックアウト自体は済んでいる 必要があるため、今回の目的には使えない。

チェックアウトの無い状態で cat-file --filters を行うと、Git-LFSのポインタファイルを取り出せる。

$ git cat-file --filters HEAD:sync/DCIM/Camera/PXL_20220331_052024030.jpg
version https://git-lfs.github.com/spec/v1
oid sha256:732a758621cc15b0fc990437170b06386af1879640e5a4a38457419a7e67f067
size 3955210

このファイルを手動で Git-LFS のsmudgeフィルタに投入することで元のファイルを得られる。

okuokuokuoku

bareリポジトリはダメ

上記の手順を bare リポジトリ(git clone --mirror 等で作ったリポジトリ)に対して実行すると、 git-lfs コマンドがクラッシュしてしまう。

$ git cat-file --filters HEAD:sync/DCIM/Camera/PXL_20220331_052024030.jpg | git lfs smudge > temp.jpg
Error: Failed to call git rev-parse --git-dir --show-toplevel: "fatal: this oper
ation must be run in a work tree\n"
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0x71a5c5]

goroutine 1 [running]:
github.com/git-lfs/git-lfs/localstorage.localObjectDir(0x0, 0xc04212effb, 0x40,
0x917db0, 0xc0421b8400)
        C:/Users/techn/go/src/github.com/git-lfs/git-lfs/localstorage/localstora
ge.go:59 +0x65

もうちょいgracefulに失敗しても良くない。。?

同様に、bareリポジトリに git lfs install することもできない。

$ git lfs install --local
Error: Failed to call git rev-parse --git-dir --show-toplevel: "fatal: this oper
ation must be run in a work tree\n"
Not in a git repository.
okuokuokuoku

ガチの手動

git-lfsのHTTP REST APIを手で叩くことも論理的には可能ではある。Git-LFSには ディスカバリプロトコル が存在して、URLから機械的にoidのURLを得られる。このURLを元に直接アクセスすれば、そもそもGitリポジトリをcloneしてくる必要もない。

http://<giteaのURL>/private/photos.git/info/lfs/objects/732a758621cc15b0fc990437170b06386af1879640e5a4a38457419a7e67f067 のように、 ベースURL + リポジトリのパス + .git/info/lfs/objects/ + <ファイルのSHA256> でDLできる。 (基本的には別途 バッチAPI を叩いてURLを得るのが正しいようだ -- 例えば このGist ではGitHubは直接S3のURLを返却しているように見える)

リポジトリのアクセスに認証が必要な場合、DL用のトークンの発行はSSH経由で行える。サーバー側の git-lfs-authenticate を呼べば良い。

$ ssh git@<giteaのSSHホスト> git-lfs-authenticate private/photos download
             {"header":{"Authorization":"Bearer ey....."},"href":"http://<URL>/private/photos.git/info/lfs"}

この header オブジェクトの内容を付けてHTTPでリクエストすれば同様の結果になる。

$ curl -H "Authorization: Bearer ey...." http://<giteaのURL>/private/photos.git/info/lfs/objects/732a758621cc15b0fc990437170b06386af1879640e5a4a38457419a7e67f067 --output temp.jpg
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 3862k  100 3862k    0     0  5919k      0 --:--:-- --:--:-- --:--:-- 5924k