The problem
Git LFS decides by path pattern which files it stores, for example
git lfs track "*.psd". Large files with a common extension (.json, .bin,
.bam), files without an extension, and files in unexpected places end up in
the Git history before anyone notices. Afterwards only a history rewrite
removes them.
git-lfs/git-lfs#282, "support
tracking by file size", has been open since 2015 and had 176 reactions and 135
comments as of 2026-10-21, which makes it the most discussed open issue in the
project. Typical cases in the thread are genomics .bam files, vendored
binaries without an extension, and game assets that grow past a limit after
their first commit.
The maintainers suggest that Git itself would be the right place for a size
filter. A pull request that adds --min-size
has been waiting for review since June 2026, and it would require the new
client on every machine. The existing hook
lfs-auto-track runs only through
npm, husky and lint-staged, and a commenter in the issue asked for a version
outside the npm ecosystem.
How it works
lfs-size-track runs as a
pre-commit hook and checks every staged file. A file above the threshold that
LFS does not already handle is tracked by its exact path with
git lfs track --filename and staged again as an LFS pointer, so the commit
contains the pointer and the .gitattributes entry. Smaller files are not
touched. It uses the stock git-lfs client, so no machine needs a patched
version.
The threshold defaults to 10 MB. It can be set with
git config lfs-size-track.threshold or --threshold in decimal or binary
units (500KB, 10MB, 1GiB), and --exclude skips paths that match a glob.
The hook is installed either with lfs-size-track install as
.git/hooks/pre-commit or through the pre-commit framework.
For repositories that already contain large files, scan lists files in HEAD
above the threshold that are stored in Git rather than LFS, and scan --history
does the same for every commit. Both print the git lfs migrate command that
would move them.
This is the output in a test repository with a 30 MB and a 2 KB .bam file
staged, at the default threshold:
$ lfs-size-track hook
lfs-size-track: data/reads.bam (30.0 MB) is now tracked by Git LFS
$ cat .gitattributes
data/reads.bam filter=lfs diff=lfs merge=lfs -text
In the same repository a 15 MB file was then committed without LFS and deleted
in the next commit. scan reports nothing for HEAD, and scan --history
finds it:
$ lfs-size-track scan
No files above 10.0 MB outside Git LFS in HEAD.
$ lfs-size-track scan --history
Files above 10.0 MB stored in Git instead of LFS (in the history):
15.0 MB old.iso
To rewrite history (changes commit IDs):
git lfs migrate import --everything --include="old.iso"
Testing
The tests create real Git repositories with git lfs install --local in a
temporary directory, write files of random bytes and check with
git cat-file whether the stored blob is an LFS pointer. A file named
data/sample [1].bam above the threshold must become a pointer while a small
file with the same extension stays in Git, and the changed .gitattributes
must be staged. Further tests cover files already matched by an LFS pattern,
excluded paths, a file with unstaged changes (exit code 1, not restaged), the
threshold from git config, scan on HEAD and with --history, the
installed hook running during a real git commit, the refusal to overwrite a
foreign hook, and the size parser. CI runs the tests on Python 3.10 to 3.13
with the git-lfs client of the runner, runs ruff, and scans the tool's own
repository with a 1 MB threshold.
Limitations
- Files are tracked by exact path. Renaming such a file later needs a new
commit through the hook, or
git lfs trackby hand. - If a large file also has unstaged changes, the hook does not restage it, because that would add the unstaged changes to the commit. It exits with code 1 and asks for the file to be staged fully.
- A file that shrinks below the threshold stays in LFS. Moving files back out of LFS is left to the user.
- Each clone needs
git lfs install, as with any LFS repository.
The code and installation instructions are at github.com/Jwrede/lfs-size-track.