Git
Git LFS
Version Control
File Management
Error Handling

Error with Previously Committed Files Which Matches New Git LFS Filter

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

This Git LFS problem appears when a repository starts tracking a file pattern in .gitattributes, but some matching files were already committed as normal Git blobs. After that change, Git or Git LFS may complain that files should have been pointers but are not. The fix depends on whether you only need to correct the current branch tip or you need to migrate the full history.

Why the Error Happens

Git LFS works through filters declared in .gitattributes. For example, a repository may start tracking *.zip or *.psd with LFS:

gitattributes
*.psd filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text

That rule affects future adds, but it does not rewrite old commits automatically. If the repository already contains matching files as regular Git content, the history now contains a mismatch:

  • old commits store full file contents
  • new rules expect LFS pointer files
  • checkout, fetch, or push operations can expose the inconsistency

A common symptom is an error similar to "file should have been a pointer". That is Git LFS telling you that the repository history and the new filter rules disagree.

Fix Only the Current State

If you do not care about rewriting old commits, the simplest fix is to start tracking the files correctly from the current commit onward.

bash
1git lfs install
2git lfs track "*.psd" "*.zip"
3git add .gitattributes
4
5git rm --cached assets/mockup.psd
6git add assets/mockup.psd
7
8git commit -m "Track design assets with Git LFS"

The key step is removing the file from the index with git rm --cached and adding it again. That forces Git to re-add the file through the LFS filter, so the next commit stores a pointer instead of the raw blob.

This approach is low risk because it does not rewrite history. The downside is that the repository still contains the large old blobs in earlier commits.

Migrate Existing History

If you want old matching files converted to LFS across history, use git lfs migrate import. That rewrites commits.

bash
1git lfs install
2git lfs track "*.psd" "*.zip"
3git add .gitattributes
4git commit -m "Add Git LFS tracking rules"
5
6git lfs migrate import --include="*.psd,*.zip"

After migration, inspect the history and then push with force:

bash
git log --stat --oneline -5
git lfs ls-files
git push --force-with-lease origin main

This is the correct approach when repository size matters and you want a clean long-term history. It is also the disruptive approach, because everyone who works on the repository must resynchronize after the rewrite.

Decide Between the Two Paths

Use the non-rewriting approach when:

  • the repository is small enough already
  • the problem affects only current files
  • changing shared history would be expensive or risky

Use history migration when:

  • old binary blobs have made clones slow
  • hosting limits are a concern
  • the team is willing to coordinate a rewrite
  • you want one consistent storage model for matching files

The important thing is to decide deliberately. Many teams run git lfs migrate import too quickly and create avoidable disruption.

Verify That the Migration Worked

Do not stop after the command succeeds. Verify the repository state.

Useful checks include:

bash
git check-attr filter -- assets/mockup.psd
git lfs ls-files
git show HEAD:assets/mockup.psd | head

If the file is tracked by LFS, git lfs ls-files should list it. Viewing the blob from Git history should show a small pointer file rather than binary content.

It is also worth doing a fresh clone into a temporary directory and checking that git lfs pull behaves as expected. That catches server-side problems before other developers hit them.

Team Coordination After a Rewrite

If history was rewritten, tell every contributor exactly what happened. After a forced push, older local branches still point to pre-migration commits.

A typical recovery sequence for collaborators is:

bash
1git fetch origin
2git checkout main
3git reset --hard origin/main
4git lfs pull

That command sequence is intentionally destructive for local main, so it should be used only after developers confirm they do not have unpushed work there. If they do have local commits, they should preserve them on a separate branch first.

Common Pitfalls

The most common mistake is assuming that editing .gitattributes retroactively converts old commits. It does not. The rules only affect future adds unless you explicitly re-add files or run a migration.

Another mistake is rewriting shared history without coordinating with the rest of the team. That creates confusing merge states and duplicated work.

It is also easy to forget that only some file patterns should move to LFS. Tracking too many small files adds complexity without much benefit.

Finally, verify server support. A local migration can look correct while pushes fail because the remote has LFS disabled or quota limits are exhausted.

Summary

  • The error appears when new LFS filters match files already committed as normal Git blobs
  • Updating .gitattributes alone does not convert old history
  • Re-adding files fixes the current tip without rewriting history
  • 'git lfs migrate import rewrites history and converts matching files across commits'
  • Validate the result with git lfs ls-files and a fresh clone
  • Coordinate carefully before force-pushing a migrated history

Course illustration
Course illustration

All Rights Reserved.