テクノロジー · 実用ガイド
clone 後に Git LFS のポインターファイルだけが残る?再 clone 前に属性とオブジェクトを監査する
clone した作業ツリーにポインターテキストが見えるのは症状であり、原因そのものではありません。ローカルの変更を保護し、正確な LFS オブジェクトを特定してから、属性とフィルター設定、ダウンロード、認証、ローカルオブジェクト、checkout の失敗を切り分けます。

Git LFS は小さなポインターを Git に保存し、大きなオブジェクトを別のストレージに置きます。作業ツリーにポインターが現れる理由には、ファイルを展開した時点で Git LFS が未導入だった、smudge を意図的に省略した、属性がパスに一致しない、オブジェクトを取得できなかった、または変更済みファイルを守るため checkout が置換を控えた、などがあります。ポインターが見えるだけではリポジトリ破損の証拠になりません。
最も安全な診断は、ポインターから属性、フィルター、ローカルキャッシュ、リモート取得、作業ツリーへの checkout まで、オブジェクトの経路を順番に追うことです。各段階で得られる証拠も修正方法も異なります。根拠なく再 clone すると、同じ設定ミスを繰り返し、帯域を消費し、重要なローカル状況を失うおそれがあります。
このガイドは読み取り中心です。履歴を書き換えず、hard reset や clean を実行せず、認証を回避せず、既存の clone も削除しません。最後に残すのは、短い証拠記録と、範囲を絞った安全な次の操作です。
1. 作業ツリーを保護し、本当にポインターか確認する
最初に `git status --short` を実行し、出力を保存します。テスト前に、ローカルで編集した可能性があるポインター状のファイルと未追跡の作業をリポジトリ外へコピーしてください。診断中は `git reset --hard`、`git clean`、履歴移行、clone の削除を行いません。
異常に小さいテキストファイルを読み取り専用で開きます。正しい Git LFS v1 ポインターには、仕様行、`oid sha256:` 行、宣言された `size` があります。相対パス、OID、サイズを記録します。見た目が似ていても形式どおり解析できない場合は、別の内容破損分岐として扱います。
利用中のバージョンが対応していれば `git lfs pointer --check --file="PATH"` を実行するか、文書化されたポインター構造と比較します。リポジトリの資格情報、署名付き URL、非公開リモートの詳細は公開用の証拠に含めません。
2. そのパスが LFS 属性の対象か確認する
影響を受けるコミットで `git check-attr -a -- "PATH"` を実行します。LFS で追跡されるはずのパスについて、Git が実際に読み取った filter、diff、merge、text 属性を確認します。作業ツリーのファイル名だけでは、現在の属性規則が一致している証明にはなりません。
未コミットのローカルコピーだけでなく、その Git バージョンに記録された `.gitattributes` を調べます。属性パターンはパスに依存します。上流 FAQ は、プラットフォーム差が誤ったパターンを露呈させたり、追跡規則が有効になる前にコミットされた古いファイルが異なる挙動を示したりする点も説明しています。
そのコミットのパスに LFS filter 属性がなければ、ここで止めます。Git LFS の導入やオブジェクト取得だけでは属性不一致を直せません。どのファイルとコミットを変更すべきかを別途レビューし、その後に renormalization や migration を検討します。
3. ローカルの Git LFS フィルターと選択状態を記録する
`git lfs version` と、秘密情報を除いた `git lfs env` を記録します。現在のユーザーとリポジトリに Git LFS が導入済みか確認し、作業ツリー作成時に `GIT_LFS_SKIP_SMUDGE=1`、`git lfs install --skip-smudge`、または同等の設定を使ったか記録します。
すべての LFS オブジェクトを取得すべきだと最初から決めつけず、include と exclude の規則を確認します。pull のマニュアルはパスフィルターを説明しており、partial clone や sparse checkout も作業ツリーへ入るパスを意図的に制限できます。
sparse-checkout の状態と partial-clone filter も記録します。既存の Git LFS issue には、partial checkout と include フィルターに関連してポインターだけが残る実例があります。ただし、属性、フィルター、取得、checkout という通常の境界を確認した後でのみ、その特定の回帰分岐を検討します。
4. オブジェクト取得と作業ツリーへの checkout を分けて考える
`git lfs pull` は fetch と checkout を組み合わせます。一方、`git lfs checkout` 単独では欠けた内容をダウンロードせず、ローカル LFS ストレージにすでにあるオブジェクトだけを使って該当ポインターを置き換えます。そのため、checkout を繰り返しても何も変わらない場合があります。
広範囲にダウンロードする前に、影響を受ける参照とパスへ取得範囲を限定します。リポジトリ構成を確認してから、たとえば `git lfs fetch REMOTE REF --include="PATH"` を実行し、正確なリモート、参照、秘密情報を除いた最初のエラーを記録します。
fetch が認証、権限、オブジェクト欠落、またはクォータのエラーを明示したら、その境界で止めます。通常の Git clone が成功しても、別の LFS オブジェクトエンドポイントが要求を受け入れたことや、その OID を保持していることの証明にはなりません。
5. checkout 前にローカルストレージの正確な OID を確認する
取得が成功したら、記録した SHA-256 OID に対応するオブジェクトがローカル LFS ストレージにあり、バイト長がポインターの宣言した size と一致することを確認します。同名ファイルから推測せず、Git LFS のコマンドとリポジトリ診断を使います。
リポジトリに適する場合は `git lfs fsck --objects` を実行して出力を保存します。ローカルオブジェクトのサイズやハッシュが一致しなければ整合性の問題です。オブジェクト自体がなければ、取得またはリモート可用性の問題がまだ残っています。
同じファイル名という理由で任意のバイナリをポインターへ上書きしないでください。内容の識別子はポインター OID です。正しい checkout は正確なオブジェクトへ解決し、無関係なファイルを変更しません。
6. checkout の変更保護を維持し、結果を正しく読む
正確なオブジェクトがローカルにあると確認してから、パスを限定して `git lfs checkout -- "PATH"` を実行します。checkout のマニュアルでは、変更済みファイルを上書きしないと説明されています。したがって、ポインター状のファイルがインデックスと異なる場合、変化がないのは導入失敗ではなく意図した保護かもしれません。
`git status --short`、`git diff -- "PATH"`、インデックスに記録されたポインターを比較します。きれいなプレースホルダーへ戻す前にローカル変更をすべてバックアップし、差分がユーザーの作業、改行破損、異常な checkout 結果のどれかを判断します。
checkout が成功したら、作業ツリーのファイルがポインターとして解析されず、サイズが宣言値に一致することを確認します。通常の Git LFS 構成で可能なら、ハッシュも OID と照合します。
証拠 | 失敗した境界 | 最小限の安全な操作 パスに LFS filter 属性がない | 属性 | 追跡規則を別途修正・レビューし、無差別に取得しない LFS が未導入、または smudge を意図的に省略 | フィルター導入 | LFS を導入または設定してから、範囲を限定して pull する fetch が認証またはオブジェクト欠落を返す | リモートアクセスまたはオブジェクト可用性 | アクセスを直すか正確な OID を復元し、再 clone はしない オブジェクトはローカルにあるが checkout が変更済みポインターを残す | 作業ツリー保護 | 変更をバックアップし、インデックスと比較してからパス限定 checkout を行う 通常確認後も partial/sparse のパスだけ失敗 | checkout の選択または回帰 | issue に昇格する前に、正確なバージョンと最小フィルター条件で再現する
7. 復旧を検証し、サポート向け証拠をまとめる
合格条件を具体化します。ポインターが解析でき、OID と宣言サイズが記録済みであること。fetch 後に同じ OID がローカルにあること。作業ツリーのパスに解決済みの内容が入り、無関係な変更がそのままであること。最後に、想定アプリケーションでファイルを開けるかを実用上の追加確認にします。
サポート依頼には、秘密情報を除いた Git と Git LFS のバージョン、OS、ポインター OID の接頭部とサイズ、`check-attr` の結果、フィルターと include/exclude の状態、リモート名、fetch の結果、ローカルオブジェクトの結果、sparse/partial checkout の状態、パス限定 checkout の結果を含めます。観測事実と結論を分けて書きます。
属性、設定、リモートアクセス、オブジェクトの存在、変更保護をすべて除外しても最小再現が失敗する場合に限り、バージョン固有の回帰として報告します。ポインターだけが残るすべての checkout を同じ既知 issue のせいにしてはいけません。
よくある質問
Git clone は成功したのに、なぜ Git LFS ファイルはダウンロードされないのですか? Git リポジトリと LFS オブジェクトサービスは別の境界です。LFS が未導入、smudge を省略、パスを除外、資格情報に失敗、またはリモートオブジェクトが欠落していても、Git はポインターファイルの clone に成功することがあります。
`git lfs checkout` は欠けたオブジェクトをダウンロードしますか? いいえ。checkout はローカル LFS ストレージにすでにあるオブジェクトだけを使います。欠けたオブジェクトは先に fetch または pull する必要があります。
ポインターを置き換えるために `git reset --hard` を実行すべきですか? 診断中は実行しないでください。hard reset は無関係な作業を失わせる可能性があり、必要な LFS オブジェクトの可用性も証明しません。先に状態、属性、OID、取得結果を記録します。
ポインターテキストが見えるのはファイル破損ですか? 必ずしもそうではありません。ポインターは正常なリポジトリデータです。問題は一致する大きなオブジェクトが作業ツリーへ展開されていないことで、複数の異なる境界が原因になり得ます。
