やりたかったこと(症状)
チームで運用しているdesign-assetsリポジトリを新しいマシンにセットアップするため、git cloneした。このリポジトリは以前からGit LFSで*.psdと*.mp4を管理している。
git clone git@github.com:example-team/design-assets.git
cd design-assets
ls -lh assets/banner_main.psd
サイズを確認したところ、本来100MB近くあるはずのファイルが、わずか130バイトしかなかった。
-rw-r--r-- 1 user user 130 Aug 3 09:12 assets/banner_main.psd
中身をcatで見てみると、画像データではなくテキストが表示された。
cat assets/banner_main.psd
version https://git-lfs.github.com/spec/v1
oid sha256:9f8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a
size 104857600
Photoshopで開こうとしても「ファイルが破損している可能性があります」というエラーで開けない。他のメンバーの環境では問題なく開けているとのことだったので、自分の環境固有の問題だと判断した。
環境
- OS: Windows 11 23H2(WSL2 Ubuntu 22.04.4上で作業)
- Git: 2.43.0
- Git LFS: 未インストール(今回の直接原因)
- リポジトリ:
design-assets(GitHub、.gitattributesでLFS設定済み) - 該当ファイル:
assets/banner_main.psd(実体は約100MB)
試したこと
最初は「クローンが途中で失敗したのでは」と考え、.gitディレクトリごと削除して再クローンした。
rm -rf design-assets
git clone git@github.com:example-team/design-assets.git
結果は同じで、banner_main.psdは130バイトのポインタ文字列のままだった。ネットワーク起因ではなく、クローン自体は正常に完了しているのに中身だけが実体化していない、という状態だと分かった。
次に、リポジトリ内に.gitattributesが存在するかを確認した。
cat .gitattributes
*.psd filter=lfs diff=lfs merge=lfs -text
*.mp4 filter=lfs diff=lfs merge=lfs -text
LFSの設定自体はリポジトリ側に正しく存在していた。ここで、自分のマシン側に何か足りないのではと考え、git lfsコマンドを実行してみた。
git lfs version
git: 'lfs' is not a git command. See 'git --help'.
この時点で、git-lfs拡張そのものがマシンにインストールされていないことに気づいた。.gitattributesのfilter=lfsが指定するスムージング(チェックアウト時にポインタを実体に置き換える処理)はgit-lfs本体がフックとして登録しないと機能しない。インストールされていない環境では、git cloneはポインタファイルの中身をそのままワーキングツリーに展開するだけになる。
原因
Git LFSは、git cloneやgit checkout時に「ポインタファイルを実データに置き換える」処理をクリーン・スムージフィルターというGitの拡張機構で行っている。このフィルターはgit lfs installを実行してはじめてグローバルのGit設定(~/.gitconfig)に登録される仕組みで、git-lfsコマンド自体がインストールされていないマシンでは登録のしようがない。
そのため、git-lfs未インストールの環境で.gitattributesにLFS設定のあるリポジトリをcloneすると、Gitはfilter=lfsを認識できず「そのままの中身」、つまりリポジトリに実際にコミットされているポインタテキスト(version / oid / sizeの3行)をそのままファイルとして書き出す。これはエラーにも警告にもならず、git clone自体は正常終了として扱われるため、ファイルサイズを確認するまで気づきにくい。
解決手順
1. git-lfsをインストールする
WSL2のUbuntu側で作業していたため、APTでインストールした。
sudo apt update
sudo apt install git-lfs
Setting up git-lfs (3.4.0-1) ...
Git LFS initialized.
2. git lfs installでフィルターを登録する
インストールしただけではリポジトリに紐付いていないため、明示的にフィルターを登録する。
git lfs install
Updated Git hooks.
Git LFS initialized.
~/.gitconfigにfilter.lfs.*の設定が追加されたことを確認した。
git config --global --get-regexp filter.lfs
filter.lfs.clean git-lfs clean -- %f
filter.lfs.smudge git-lfs smudge -- %f
filter.lfs.process git-lfs filter-process
filter.lfs.required true
3. 既存のワーキングツリーをLFS実体で上書きする
再クローンせずに済むよう、既存の作業ディレクトリ内でポインタファイルを実体に置き換えるgit lfs pullを実行した。
cd design-assets
git lfs pull
Downloading LFS objects: 50% (1/2), 52 MB | 8.1 MB/s
Downloading LFS objects: 100% (2/2), 100 MB | 8.4 MB/s, done.
4. ファイルサイズを確認する
ls -lh assets/banner_main.psd
-rw-r--r-- 1 user user 100M Aug 3 09:41 assets/banner_main.psd
実データのサイズに戻っていることを確認した。
動作確認
Photoshopでassets/banner_main.psdを開き、正常にレイヤーが読み込まれることを確認した。念のため、まっさらな別ディレクトリに再クローンしても同じ結果になるかを試した。
git clone git@github.com:example-team/design-assets.git design-assets-check
cd design-assets-check
ls -lh assets/banner_main.psd
-rw-r--r-- 1 user user 100M Aug 3 09:55 assets/banner_main.psd
git lfs installを済ませた環境であれば、cloneの時点から実体としてチェックアウトされることを確認できた。
まとめ
git-lfs未インストールの環境でcloneすると、LFS管理下のファイルはversion/oid/sizeが書かれたポインタ文字列のままワーキングツリーに展開される。これはエラーにならないため、ファイルサイズを見るまで気づきにくい。- 対処は
git-lfsのインストールとgit lfs installによるフィルター登録、既存クローンなら追加でgit lfs pull。新しいマシンをセットアップする際は、clone前にgit lfs installを済ませておくのが確実。 - 同種の「サイズが極端に小さいファイルが実体を持たない」症状は、動画・デザインファイル・モデルファイルなど、LFSで管理しがちな種類のファイルを扱うリポジトリで起こりやすい。中身を
catしてversion https://git-lfs.github.com/spec/v1が出てきたら、まずこの原因を疑うとよい。
よくある質問
Q: git lfs installはリポジトリごとに実行する必要がありますか?
git lfs install自体はマシン単位(グローバルGit設定)で一度実行すれば十分です。以降はそのマシン上でLFS対応リポジトリをcloneするたびに自動でフィルターが働きます。ただしgit-lfs本体のインストールは今回のようにマシンが変わるたびに必要です。
Q: 既にポインタファイルのままcloneしてしまった場合、再クローンは必須ですか?
不要です。git-lfsをインストールしgit lfs installを実行したあとで、既存の作業ディレクトリ内でgit lfs pullを実行すれば、ポインタファイルを実体に置き換えられます。
Q: CI環境でも同じ問題が起きますか?
起きます。CIのビルドイメージにgit-lfsが入っていないと、checkoutアクション等でLFSファイルがポインタのまま展開され、ビルドが実体を期待する処理で失敗します。CI側の環境にもgit-lfsのインストールとgit lfs install(もしくは対応するCIアクションのLFSオプション)が必要です。