# Git LFS ## Remove Git LFS from repository, keep files For example, I had to do this because of Obsidian's sync. [source](https://github.com/git-lfs/git-lfs/issues/3026) > Thanx, that helped me a lot while I was migrating from BitBucket to AWS CodeCommit. Some helpful hints: > > - commit & push everything > - remove hooks > `git lfs uninstall` > - remove lfs stuff from `.gitattributes` > - list lfs files using > `git lfs ls-files | sed -r 's/^.{13}//' > files.txt` > - run git rm --cached for each file > `while read line; do git rm --cached "$line"; done < files.txt` > - run git add for each file > `while read line; do git add "$line"; done < files.txt` > - commit everything > `git add .gitattributes` > `git commit -m "unlfs"` > `git push origin` > - check that no lfs files left > `git lfs ls-files` > - remove junk > `rm -rf .git/lfs` > - you're all done > (but unlinked junk is within BitBucket Git LFS storage still) --- ## File Locking Adapted from the [Git LFS wiki](https://github.com/git-lfs/git-lfs/wiki/File-Locking). Prevents concurrent edits on large binary files by claiming exclusive access — avoids merge conflicts that are nearly impossible to resolve in binaries. ### Track Lockable Files Mark file types as lockable using the `--lockable` flag: ```bash git lfs track "*.jpg" --lockable git lfs track "*.psd" --lockable ``` This generates a `.gitattributes` entry: ```text *.jpg filter=lfs diff=lfs merge=lfs -text lockable ``` **Key benefit:** Lockable files automatically become read-only locally, preventing accidental edits without securing a lock first. ### Managing Locks **Lock a file for editing:** ```bash git lfs lock images/foo.jpg ``` **View all active locks:** ```bash git lfs locks ``` **View locks for a specific path:** ```bash git lfs locks --path images/ ``` **Release your lock:** ```bash git lfs unlock images/foo.jpg ``` **Force unlock (admin only on some servers):** ```bash git lfs unlock images/foo.jpg --force ``` Since v3.0.0, you can specify multiple file paths in single commands. ### Important Notes - Server implementations vary in permissions requirements - Git LFS verifies lock status during pushes but won't block pushes if the server lacks locking API support - This feature requires Git LFS v2.0.0 or later - Lockable files become read-only in your working directory until you lock them --- ## Smudge and Clean Filters [source](https://git-lfs.com/) ### What are smudge and clean? Git LFS uses two Git filter processes: ### Smudge (pointer → real file) - Happens on **checkout** - Takes the small LFS pointer file stored in Git and replaces it with the actual large file content in your working directory - **Smudge = resolving pointers into real files** ### Clean (real file → pointer) - Happens on **add/commit** - Takes your large file and replaces it with a small pointer file in the Git object database - Actual large content is stored in LFS storage - **Clean = converting real files to pointers** ```text Checkout: pointer → [smudge] → real file Commit: real file → [clean] → pointer ``` --- ## Free Up Space: Replace Files with Pointers ### Convert working copy to pointers temporarily **Use case:** Save disk space by keeping only pointer files locally instead of large LFS content. ### Go light (pointers + prune) ```bash # 0) Save local work if needed git stash -u # 1) Stop auto-smudging LFS files git lfs install --local --skip-smudge # 2) Rewrite the worktree to contain pointer files git reset --hard HEAD # 3) Free space by removing LFS blobs from local cache # Tip: add --dry-run first to preview what would be deleted git lfs prune --force --verify-remote --recent=0 # 4) Check space freed du -sh .git/lfs/objects ``` ### Rehydrate real LFS content later ```bash # 1) Re-enable smudging git lfs install --local # 2) Fetch & populate actual content git lfs pull # fetch LFS objects for HEAD git lfs checkout # replace pointers with real files ``` ### Selective hydration (keep only specific paths) ```bash # Keep smudge disabled git lfs install --local --skip-smudge # Fetch & populate only what you need git lfs pull --include="assets/models/**,data/samples/**" git lfs checkout --include="assets/models/**,data/samples/**" # Prune everything else git lfs prune --force --verify-remote --recent=0 ``` ### Temporary one-off (without config change) ```bash GIT_LFS_SKIP_SMUDGE=1 git checkout -f . ``` ### Important notes - `--skip-smudge` disables the smudge filter, so checkouts leave pointer files instead of downloading large files - `git reset --hard` and `git checkout -f` will **discard uncommitted changes** - stash first! - `git lfs prune` deletes unused large objects from `.git/lfs/objects` - `--verify-remote` ensures content exists on remote before pruning - `git lfs uninstall` only removes filters, doesn't rewrite working tree or prune cache