# PowerShell script to find binary files NOT tracked by Git LFS # Run this from your repository root param( [string]$RepoPath = ".", [switch]$ShowLFSStatus = $false ) $ErrorActionPreference = "Continue" # Common binary file extensions that should be in LFS $binaryExtensions = @( # Images 'bmp', 'exr', 'gif', 'hdr', 'jpg', 'jpeg', 'png', 'tga', 'tif', 'tiff', 'webp', 'heic', 'HEIC', 'ico', 'cur', 'ani', 'xcf', 'psd', 'ai', 'af', 'eps', 'raw', 'cr2', 'nef', 'dng', # 3D/CG '3ds', 'abc', 'blend', 'blend1', 'blend2', 'bvh', 'c4d', 'dae', 'fbx', 'fbxkey', 'ma', 'max', 'mb', 'obj', 'usd', 'usdz', 'vdb', 'bphys', 'bobj', 'bvel', 'bpointcache', 'blob', 'unitypackage', 'skp', 'stl', 'ply', 'glb', 'gltf', '3mf', 'lwo', 'lws', # Character Creator / Reallusion 'ccAvatar', 'ccProject', 'ccCloth', 'ccProp', 'ccScene', 'ccHair', 'rlMotion', 'rlPose', 'iAvatar', 'iMotion', 'iProp', 'iMaterial', 'rlHead', 'rlHair', 'rlScene', 'rlSkintex', '3dxProfile', # Houdini 'hiplc', 'bgeo', 'bgeo.sc', 'hdanc', 'otllc', 'otlnc', # Video 'avi', 'mkv', 'mov', 'MOV', 'mp4', 'webm', 'm4v', 'mpg', 'mpeg', 'wmv', 'flv', 'f4v', # Audio 'mp3', 'wav', 'm4a', 'aac', 'ogg', 'flac', 'wma', 'aiff', 'au', 'ra', 'ram', 'mid', 'midi', 'ac3', 'dts', # Archives '7z', 'bz2', 'gz', 'gzip', 'lzma', 'rar', 'tar', 'xz', 'z', 'zip', 'whl', 'npz', 'pkl', 'pickle', 'joblib', 'parquet', 'feather', # Documents 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf', 'odt', 'ods', 'odp', 'rtf', # Adobe 'aegraphic', 'aep', 'prel', 'prin', 'prmf', 'prproj', 'ai', 'psd', 'pk', 'pkf', # Data/Cache 'h5', 'hdf5', 'dat', 'db', 'sqlite', 'sqlite3', 'mdb', 'ldb', 'frm', 'ibd', 'npy', 'pkl', 'pickle', 'joblib', 'caffemodel', 'pth', 'onnx', 'pb', 'tflite', # Binaries 'exe', 'dll', 'so', 'dylib', 'pyd', 'bin', 'o', 'a', 'lib', 'obj', 'app', 'msi', 'msp', 'msm', 'dmg', 'pkg', 'deb', 'rpm', 'snap', 'flatpak', 'AppImage', # Fonts 'ttf', 'otf', 'woff', 'woff2', 'eot', 'pfm', 'afm', 'tfm', # Other 'uni', 'pdn', 'pur', 'lnk', 'swf', 'fla', 'wasm', 'loom', 'mat', 'fbxkey', 'ffp3', 'data', 'sqlite3', 'db', 'raw', 'dpx', 'drp', 'lut', 'cube', 'spi1d', 'spi3d', 'clf', # Substance 'sbs', 'sbsar', 'spp', 'sbsprs', 'sbscfg', # Flip Fluids 'bphys', 'bobj', 'bvel', 'bpointcache', 'blob', 'ffp3', # Game engines 'uasset', 'umap', 'upk', 'udk', 'pak', 'unitypackage', 'prefab', 'asset', 'meta' ) function Test-IsBinaryExtension { param([string]$extension) return $binaryExtensions -contains $extension } function Get-FileSize { param([string]$path) try { $file = Get-Item $path -ErrorAction SilentlyContinue if ($file) { if ($file.Length -gt 1MB) { return "{0:N2} MB" -f ($file.Length / 1MB) } elseif ($file.Length -gt 1KB) { return "{0:N2} KB" -f ($file.Length / 1KB) } else { return "$($file.Length) B" } } } catch { return "Unknown" } return "Unknown" } # Get absolute path $absPath = Resolve-Path $RepoPath Write-Host "Scanning repository for untracked binaries: $absPath" -ForegroundColor Cyan Write-Host "" # Get list of ALL files tracked by Git Write-Host "Getting files tracked by Git..." -ForegroundColor Yellow $allGitFiles = git ls-files 2>$null # Get list of files tracked by LFS Write-Host "Getting files tracked by LFS..." -ForegroundColor Yellow $lfsFiles = git lfs ls-files 2>$null | ForEach-Object { # Parse the LFS output format: * or - if ($_ -match '^[a-f0-9]+\s+[-*]\s+(.+)$') { $matches[1] } } # Create a hashtable for fast lookup of LFS files $lfsFileLookup = @{} foreach ($file in $lfsFiles) { $lfsFileLookup[$file] = $true } Write-Host "Total Git-tracked files: $($allGitFiles.Count)" -ForegroundColor Gray Write-Host "Total LFS-tracked files: $($lfsFiles.Count)" -ForegroundColor Gray Write-Host "" # Find binary files that are NOT in LFS $untrackedBinaries = @() $extensionSummary = @{} foreach ($file in $allGitFiles) { # Skip if empty if ([string]::IsNullOrWhiteSpace($file)) { continue } # Skip if already in LFS if ($lfsFileLookup.ContainsKey($file)) { continue } # Get extension (with error handling for weird filenames) try { $extension = [System.IO.Path]::GetExtension($file).TrimStart('.') } catch { continue # Skip files with problematic names } # Check if it's a known binary extension if (Test-IsBinaryExtension -extension $extension) { $fullPath = Join-Path $absPath $file $fileSize = Get-FileSize -path $fullPath $untrackedBinaries += [PSCustomObject]@{ File = $file Extension = $extension Size = $fileSize } # Track summary if (-not $extensionSummary.ContainsKey($extension)) { $extensionSummary[$extension] = 0 } $extensionSummary[$extension]++ } } # Display results if ($untrackedBinaries.Count -eq 0) { Write-Host "No untracked binary files found!" -ForegroundColor Green Write-Host "All binary files are properly tracked by Git LFS." -ForegroundColor Green } else { Write-Host "Found $($untrackedBinaries.Count) binary files tracked by Git (not LFS):" -ForegroundColor Red Write-Host "" # Group by extension for display $groupedByExt = $untrackedBinaries | Group-Object -Property Extension | Sort-Object Count -Descending foreach ($group in $groupedByExt) { $groupName = $group.Name $groupCount = $group.Count Write-Host " .$groupName ($groupCount files):" -ForegroundColor Yellow foreach ($item in $group.Group | Select-Object -First 10) { Write-Host " - $($item.File) ($($item.Size))" -ForegroundColor Gray } if ($groupCount -gt 10) { Write-Host " ... and $($groupCount - 10) more" -ForegroundColor DarkGray } } Write-Host "" Write-Host "========================================" -ForegroundColor Red Write-Host "SUGGESTED .gitattributes ADDITIONS:" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan # Generate suggested gitattributes entries $sortedExts = $extensionSummary.GetEnumerator() | Sort-Object Value -Descending foreach ($ext in $sortedExts) { $extName = $ext.Key Write-Host "*.$extName filter=lfs diff=lfs merge=lfs -text" -ForegroundColor White } Write-Host "" Write-Host "To fix these files, add the above lines to your .gitattributes file," -ForegroundColor Yellow Write-Host "then run: git add --renormalize ." -ForegroundColor Yellow } Write-Host "" # Optional: Show full LFS status if ($ShowLFSStatus) { Write-Host "========================================" -ForegroundColor Cyan Write-Host "Current LFS Status:" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan git lfs status 2>&1 | ForEach-Object { Write-Host $_ } }