Skip to content

Instantly share code, notes, and snippets.

@nirgeier
Created January 20, 2026 10:07
Show Gist options
  • Select an option

  • Save nirgeier/abf1778ddca662deb5b0fc386f639cfa to your computer and use it in GitHub Desktop.

Select an option

Save nirgeier/abf1778ddca662deb5b0fc386f639cfa to your computer and use it in GitHub Desktop.
LFS
#!/bin/bash
set -e
# -------------------------------------------------------------------------
# Git LFS (Large File Storage) .gitattributes
# -------------------------------------------------------------------------
# --- Images ---
*.jpg filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text
*.ai filter=lfs diff=lfs merge=lfs -text
*.webp filter=lfs diff=lfs merge=lfs -text
*.svgz filter=lfs diff=lfs merge=lfs -text
*.tiff filter=lfs diff=lfs merge=lfs -text
*.tif filter=lfs diff=lfs merge=lfs -text
*.bmp filter=lfs diff=lfs merge=lfs -text
*.ico filter=lfs diff=lfs merge=lfs -text
*.jif filter=lfs diff=lfs merge=lfs -text
*.jp2 filter=lfs diff=lfs merge=lfs -text
*.jpx filter=lfs diff=lfs merge=lfs -text
*.j2k filter=lfs diff=lfs merge=lfs -text
*.j2c filter=lfs diff=lfs merge=lfs -text
*.fpx filter=lfs diff=lfs merge=lfs -text
*.pcd filter=lfs diff=lfs merge=lfs -text
*.xcf filter=lfs diff=lfs merge=lfs -text
*.tga filter=lfs diff=lfs merge=lfs -text
*.dds filter=lfs diff=lfs merge=lfs -text
*.exr filter=lfs diff=lfs merge=lfs -text
*.hdr filter=lfs diff=lfs merge=lfs -text
*.raw filter=lfs diff=lfs merge=lfs -text
*.cr2 filter=lfs diff=lfs merge=lfs -text
*.nef filter=lfs diff=lfs merge=lfs -text
*.orf filter=lfs diff=lfs merge=lfs -text
*.sr2 filter=lfs diff=lfs merge=lfs -text
# --- Audio ---
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
*.m4a filter=lfs diff=lfs merge=lfs -text
*.wma filter=lfs diff=lfs merge=lfs -text
*.aac filter=lfs diff=lfs merge=lfs -text
*.flac filter=lfs diff=lfs merge=lfs -text
*.aiff filter=lfs diff=lfs merge=lfs -text
*.ra filter=lfs diff=lfs merge=lfs -text
*.mid filter=lfs diff=lfs merge=lfs -text
*.midi filter=lfs diff=lfs merge=lfs -text
*.aif filter=lfs diff=lfs merge=lfs -text
*.ape filter=lfs diff=lfs merge=lfs -text
*.opus filter=lfs diff=lfs merge=lfs -text
# --- Video ---
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.mov filter=lfs diff=lfs merge=lfs -text
*.avi filter=lfs diff=lfs merge=lfs -text
*.wmv filter=lfs diff=lfs merge=lfs -text
*.flv filter=lfs diff=lfs merge=lfs -text
*.webm filter=lfs diff=lfs merge=lfs -text
*.mkv filter=lfs diff=lfs merge=lfs -text
*.m4v filter=lfs diff=lfs merge=lfs -text
*.mpg filter=lfs diff=lfs merge=lfs -text
*.mpeg filter=lfs diff=lfs merge=lfs -text
*.3gp filter=lfs diff=lfs merge=lfs -text
*.3g2 filter=lfs diff=lfs merge=lfs -text
*.asf filter=lfs diff=lfs merge=lfs -text
*.rm filter=lfs diff=lfs merge=lfs -text
*.swf filter=lfs diff=lfs merge=lfs -text
*.vob filter=lfs diff=lfs merge=lfs -text
*.ts filter=lfs diff=lfs merge=lfs -text
*.m2ts filter=lfs diff=lfs merge=lfs -text
# --- 3D Models & Assets ---
*.fbx filter=lfs diff=lfs merge=lfs -text
*.obj filter=lfs diff=lfs merge=lfs -text
*.blend filter=lfs diff=lfs merge=lfs -text
*.blend1 filter=lfs diff=lfs merge=lfs -text
*.max filter=lfs diff=lfs merge=lfs -text
*.maya filter=lfs diff=lfs merge=lfs -text
*.3ds filter=lfs diff=lfs merge=lfs -text
*.dae filter=lfs diff=lfs merge=lfs -text
*.stl filter=lfs diff=lfs merge=lfs -text
*.ply filter=lfs diff=lfs merge=lfs -text
*.glb filter=lfs diff=lfs merge=lfs -text
*.gltf filter=lfs diff=lfs merge=lfs -text
*.ma filter=lfs diff=lfs merge=lfs -text
*.mb filter=lfs diff=lfs merge=lfs -text
*.dwg filter=lfs diff=lfs merge=lfs -text
*.dxf filter=lfs diff=lfs merge=lfs -text
*.c4d filter=lfs diff=lfs merge=lfs -text
*.lwo filter=lfs diff=lfs merge=lfs -text
*.lws filter=lfs diff=lfs merge=lfs -text
*.lxo filter=lfs diff=lfs merge=lfs -text
*.abc filter=lfs diff=lfs merge=lfs -text
*.3dm filter=lfs diff=lfs merge=lfs -text
*.spp filter=lfs diff=lfs merge=lfs -text
# --- Archives & Compressed ---
*.zip filter=lfs diff=lfs merge=lfs -text
*.tar filter=lfs diff=lfs merge=lfs -text
*.gz filter=lfs diff=lfs merge=lfs -text
*.7z filter=lfs diff=lfs merge=lfs -text
*.rar filter=lfs diff=lfs merge=lfs -text
*.iso filter=lfs diff=lfs merge=lfs -text
*.dmg filter=lfs diff=lfs merge=lfs -text
*.deb filter=lfs diff=lfs merge=lfs -text
*.rpm filter=lfs diff=lfs merge=lfs -text
*.apk filter=lfs diff=lfs merge=lfs -text
*.jar filter=lfs diff=lfs merge=lfs -text
*.war filter=lfs diff=lfs merge=lfs -text
*.ear filter=lfs diff=lfs merge=lfs -text
*.bz2 filter=lfs diff=lfs merge=lfs -text
*.xz filter=lfs diff=lfs merge=lfs -text
*.lz filter=lfs diff=lfs merge=lfs -text
*.tgz filter=lfs diff=lfs merge=lfs -text
*.tbz2 filter=lfs diff=lfs merge=lfs -text
*.sit filter=lfs diff=lfs merge=lfs -text
*.sitx filter=lfs diff=lfs merge=lfs -text
*.z filter=lfs diff=lfs merge=lfs -text
# --- Documents ---
*.pdf filter=lfs diff=lfs merge=lfs -text
*.doc filter=lfs diff=lfs merge=lfs -text
*.ppt filter=lfs diff=lfs merge=lfs -text
*.docx filter=lfs diff=lfs merge=lfs -text
*.pptx filter=lfs diff=lfs merge=lfs -text
*.xlsx filter=lfs diff=lfs merge=lfs -text
*.odt filter=lfs diff=lfs merge=lfs -text
*.ods filter=lfs diff=lfs merge=lfs -text
*.odp filter=lfs diff=lfs merge=lfs -text
*.epub filter=lfs diff=lfs merge=lfs -text
*.chm filter=lfs diff=lfs merge=lfs -text
*.key filter=lfs diff=lfs merge=lfs -text
*.numbers filter=lfs diff=lfs merge=lfs -text
*.pages filter=lfs diff=lfs merge=lfs -text
# --- Executables, Libraries & Binaries ---
*.exe filter=lfs diff=lfs merge=lfs -text
*.dll filter=lfs diff=lfs merge=lfs -text
*.so filter=lfs diff=lfs merge=lfs -text
*.dylib filter=lfs diff=lfs merge=lfs -text
*.bin filter=lfs diff=lfs merge=lfs -text
*.dat filter=lfs diff=lfs merge=lfs -text
*.db filter=lfs diff=lfs merge=lfs -text
*.sqlite filter=lfs diff=lfs merge=lfs -text
*.msi filter=lfs diff=lfs merge=lfs -text
*.pdb filter=lfs diff=lfs merge=lfs -text
*.a filter=lfs diff=lfs merge=lfs -text
*.lib filter=lfs diff=lfs merge=lfs -text
*.o filter=lfs diff=lfs merge=lfs -text
*.obj filter=lfs diff=lfs merge=lfs -text
*.pyc filter=lfs diff=lfs merge=lfs -text
# --- Design & Fonts ---
*.otf filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
*.woff filter=lfs diff=lfs merge=lfs -text
*.woff2 filter=lfs diff=lfs merge=lfs -text
*.eot filter=lfs diff=lfs merge=lfs -text
*.sketch filter=lfs diff=lfs merge=lfs -text
*.xd filter=lfs diff=lfs merge=lfs -text
*.fig filter=lfs diff=lfs merge=lfs -text
*.psb filter=lfs diff=lfs merge=lfs -text
*.ind filter=lfs diff=lfs merge=lfs -text
*.indd filter=lfs diff=lfs merge=lfs -text
*.indt filter=lfs diff=lfs merge=lfs -text
# https://gemini.google.com/share/f40e23468348
# change the directory to the first argument
cd $1 || {
echo "Error: Could not change to directory $1"
exit 1
}
# Define file outputs
LFS_RAW_LIST="lfs_debug_raw.txt"
LFS_PATHS_LIST="lfs_files_paths.txt"
LFS_NAMES_LIST="lfs_files_names.txt"
echo "========================================================"
echo " LFS Cleanup Script using BFG"
echo "========================================================"
# Check if git lfs is available
if ! git lfs version &>/dev/null; then
echo "Error: git-lfs is not installed or not in PATH."
exit 1
fi
echo "[1/4] Preparing branches and scanning for LFS files..."
# Fetch all remotes
git fetch --all
# Loop over all remote branches to ensure we have local copies for BFG to update
# BFG Repo-Cleaner automatically updates all local branches (refs/heads/*).
# By creating local tracking branches for all remote branches, we ensure BFG cleans ALL of them.
echo "Checking out all remote tracking branches..."
git for-each-ref --format='%(refname:short)' refs/remotes/origin/ | while read -r remote; do
# Skip HEAD
if [[ "$remote" == *"HEAD" ]]; then
continue
fi
# Remove 'origin/' to get the branch name
branch=${remote#origin/}
# Create local branch if it doesn't exist
if ! git show-ref --verify --quiet refs/heads/"$branch"; then
echo "Creating local branch: $branch matching $remote"
git branch --track "$branch" "$remote"
else
echo "Verified local branch: $branch"
fi
done
# Scan all refs for LFS files
echo "Scanning ALL refs for LFS files..."
git lfs ls-files --all >"$LFS_RAW_LIST"
if [ ! -s "$LFS_RAW_LIST" ]; then
echo "No LFS files found in the repository history."
exit 0
fi
# Extract file paths (strip OID and status char)
# Format is: <oid> < * | - > <path>
cat "$LFS_RAW_LIST" | sed 's/^[^ ]* . //' | sort | uniq >"$LFS_PATHS_LIST"
# Extract just filenames (BFG --delete-files works on filenames, not path globs)
cat "$LFS_PATHS_LIST" | awk -F/ '{print $NF}' | sort | uniq >"$LFS_NAMES_LIST"
COUNT=$(wc -l <"$LFS_NAMES_LIST")
echo "Found $COUNT unique LFS filenames."
echo "Full paths saved to: $LFS_PATHS_LIST"
echo "Filenames saved to: $LFS_NAMES_LIST"
echo "--------------------------------------------------------"
cat "$LFS_NAMES_LIST"
echo "--------------------------------------------------------"
# Check for BFG
echo "[2/4] Checking for BFG Repo-Cleaner..."
if command -v bfg &>/dev/null; then
BFG_CMD="bfg"
elif [ -f bfg.jar ]; then
BFG_CMD="java -jar bfg.jar"
elif [ -n "$BFG_PATH_JAR" ]; then
BFG_CMD="java -jar $BFG_PATH_JAR"
else
echo "Error: 'bfg' command not found and bfg.jar not in current directory."
echo "Please download bfg.jar from https://rtyley.github.io/bfg-repo-cleaner/ and place it here,"
echo "or install 'bfg' via package manager (e.g., 'brew install bfg')."
exit 1
fi
echo "Using: $BFG_CMD"
# Construct glob string
# Join lines with commas
FILES_GLOB=$(paste -sd "," "$LFS_NAMES_LIST")
# If multiple files, ensure it is treated as a list by BFG wrapping in {}
if [ "$COUNT" -gt 1 ]; then
FILES_GLOB="{$FILES_GLOB}"
fi
echo "[3/4] Running BFG to remove LFS files..."
echo "Target glob: $FILES_GLOB"
# Run BFG
# --delete-files removes the file from history
# --no-blob-protection ensures even recent files are removed
$BFG_CMD --delete-files "$FILES_GLOB" --no-blob-protection
echo "[4/4] Finalizing cleanup (git gc)..."
# Expire reflog and prune to physically remove objects
git reflog expire --expire=now --all && git gc --prune=now --aggressive
echo "========================================================"
echo "Cleanup Complete!"
echo "NOTE: BFG has rewritten your commit history."
echo "Changes are currently local."
echo "To apply changes remotely, run: git push --force --all"
echo "========================================================"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment