← Debugging Guides

阅读中文版本

Git LFS pointer file — Why the Binary Is Just Text

Diagnose Git LFS pointer files by checking filters, attributes, and lfs status, then install hooks, pull objects, or migrate files committed without LFS.

beginnerdebugginggitgit-lfs

Symptoms

  • An image, model, or archive opens as a small text file starting with version https://git-lfs.github.com/spec/v1
  • The file size in the working tree is a few hundred bytes instead of megabytes
  • Builds fail because a binary asset cannot be parsed
  • CI checks out the repository but assets remain pointers

Possible causes

  • Git LFS was not installed when the repository was cloned, so the smudge filter never ran
  • CI used GIT_LFS_SKIP_SMUDGE=1 or a checkout action without LFS enabled
  • The file was committed before .gitattributes marked it for LFS
  • LFS objects were not fetched because of bandwidth limits or a missing remote

Diagnosis steps

Confirm the file is a pointer

file assets/model.bin && head -3 assets/model.bin && wc -c assets/model.bin

Interpretation

A pointer begins with the LFS spec version and contains oid and size lines. The working tree size is tiny while the real object is large.

Check repository LFS state and attributes

git lfs ls-files | head -20 && git check-attr filter diff merge -- assets/model.bin

Interpretation

lfs ls-files lists tracked paths with an asterisk when the object is present locally. The attribute output should show filter=lfs; otherwise the file is not managed by LFS.

Verify the smudge filter configuration

git config --get filter.lfs.smudge && git config --get filter.lfs.required && git lfs env | head -20

Interpretation

A missing smudge command means Git LFS hooks are not installed in this clone. git lfs env shows the endpoint and local storage paths.

Test object availability

git lfs pull && git lfs checkout && git lfs status

Interpretation

Download errors here indicate missing objects on the remote or authentication problems. A successful pull replaces pointers with content.

Root cause

Git LFS stores large files as small pointer blobs in Git and keeps the content on a separate LFS server. The smudge filter expands pointers during checkout, but only when Git LFS is installed and the file is matched by .gitattributes. A clone without the filter, a CI checkout that skips smudge, or a file committed before the attribute existed leaves the pointer as the working-tree content.

Fix

Install Git LFS and initialize hooks with git lfs install, then run git lfs pull and git lfs checkout. In CI, enable LFS in the checkout step or set git lfs install --force before checkout. If files were committed as regular blobs, add the correct .gitattributes pattern and rewrite history with git lfs migrate import --include, coordinating with the team because it changes commit IDs.

Risk note

git lfs migrate rewrites history and requires every collaborator to re-clone or reset. Removing the smudge filter makes pointers appear as real files again. Deleting LFS objects from the remote to save space breaks old commits that reference them.

Verify the fix

Run file and wc -c on the asset to confirm it is the expected binary size, and check git lfs ls-files shows an asterisk for the path. Rebuild the project and verify the image or model loads, then repeat the CI checkout from a fresh clone.

The binary was replaced by a stub

Git LFS keeps a pointer in the repository and the real content on a separate server. If the smudge filter did not run, the working tree contains only the pointer:

version https://git-lfs.github.com/spec/v1
oid sha256:6f1c2a9e8b7d4c3a1f0e9d8c7b6a5f4e3d2c1b0a9f8e7d6c5b4a3f2e1d0c9b8a
size 48271360

Builds then fail with “not a valid image” or “unexpected end of file” even though git status is clean.

Check filters before re-downloading

git lfs ls-files
git check-attr filter diff merge -- assets/model.bin
git config --get filter.lfs.smudge
git lfs env

filter: lfs and a configured smudge command mean the repository is set up correctly and the object simply was not fetched. No filter means the file is tracked as a normal blob and git lfs pull will not help.

Restore the content

git lfs install
git lfs pull
git lfs checkout

For CI, enable LFS in the checkout action or run git lfs install --force before checking out. If a file was committed as a regular blob, add .gitattributes and migrate:

git lfs track "*.psd"
git lfs migrate import --include="*.psd" --everything

Migration rewrites commit IDs, so schedule it with the team and force-push deliberately.

Verify

file assets/model.bin should identify the real format, and wc -c should match the size in the pointer. git lfs ls-files should show * next to the path, meaning the object exists locally. Finally, rerun the build, and test a fresh CI clone so the fix is not relying on your local LFS cache.