#!/usr/bin/env bash # Verify Git LFS health for this repository. # # Why: .gitattributes routes content through the "lfs" filter, but that filter only # exists after `git lfs install` writes filter.lfs.* into git config. Without it, # git does NOT fail on a filtered path — it stores the file as an ordinary blob with # no warning, and the mistake is only noticed later when the file is huge and # unversioned in LFS. Run this before committing any binary content. # # Usage: Tools/check-lfs.sh (exit 0 = healthy, 1 = problem found) set -euo pipefail cd "$(dirname "$0")/.." fail=0 lfs_patterns=$(grep -c 'filter=lfs' .gitattributes || true) if [ "${lfs_patterns:-0}" -eq 0 ]; then echo "ERROR: .gitattributes has no filter=lfs rules." >&2 exit 1 fi if ! command -v git-lfs >/dev/null 2>&1; then echo "ERROR: git-lfs is not installed. LFS-tracked files would be stored as ordinary blobs." >&2 echo " Install git-lfs, run 'git lfs install', then re-check. See Docs/environment.md." >&2 fail=1 fi if ! git config --get filter.lfs.process >/dev/null 2>&1; then echo "ERROR: git config has no filter.lfs.process; the lfs filter is not active." >&2 echo " Run 'git lfs install' in this repository." >&2 fail=1 fi pointer_prefix="version https://git-lfs" checked=0 while IFS= read -r path; do [ -n "$path" ] || continue filter=$(git check-attr filter -- "$path" | awk -F': ' '{print $NF}') [ "$filter" = "lfs" ] || continue checked=$((checked + 1)) blob_head=$(git cat-file -p ":$path" 2>/dev/null | head -c 64 | tr -d '\0' || true) case "$blob_head" in "$pointer_prefix"*) ;; *) echo "ERROR: '$path' is LFS-tracked by .gitattributes but is stored as a plain blob." >&2 echo " Fix with: git lfs migrate import --include='$path' (rewrites history)." >&2 fail=1 ;; esac done < <(git ls-files) if [ "$fail" -eq 0 ]; then echo "LFS check OK: $checked LFS-tracked file(s) stored as pointers." fi exit "$fail"