# 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