Find what's making your repository huge
My .git folder is enormous — how do I find the biggest files in history?
Short answer
git count-objects -vH tells you the total size; combining git rev-list --objects with git cat-file --batch-check lists the largest blobs by name. Deleting the files now won't shrink anything — they have to be purged from history.
git count-objects -vH
Shows how much space the object database is actually using
Does this match your situation?
- Cloning takes many minutes for a small codebase.
- .git is far larger than your working directory.
- A push is rejected for exceeding a file size limit.
- CI checkouts are slow and getting slower.
Step-by-step fix
Measure the damage
size-pack is the number that matters — the compressed size of all history. Compare it to your working directory to see how disproportionate things are.
step 1git count-objects -vH du -sh .gitShow the PowerShell (Windows) version
PowerShell (Windows)git count-objects -vH "{0:N1} MB" -f ((Get-ChildItem .git -Recurse -File | Measure-Object Length -Sum).Sum / 1MB)List the biggest objects with their filenames
This is the canonical recipe: enumerate every object, ask for its size, keep the blobs, sort, and take the top few. The fourth column is the path.
step 2git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | awk '/^blob/ {print $3, $4}' | sort -rn | head -20Show the PowerShell (Windows) version
PowerShell (Windows)git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | Where-Object { $_ -like 'blob*' } | ForEach-Object { $p = $_ -split ' '; [PSCustomObject]@{ Size = [long]$p[2]; Path = $p[3] } } | Sort-Object Size -Descending | Select-Object -First 20Check whether the file still exists
Often the culprit was deleted long ago and only survives in history. That's precisely why the repository never shrank when it was removed.
step 3git log --all --oneline -- "**/big-file.psd" | head ls -la big-file.psd 2>/dev/null || echo "not in the working tree - history only"Purge the worst offenders from history
Work on a fresh clone. Strip by size or by path, then force-push and have everyone re-clone.
step 4git clone --mirror . ../repo-backup.git pip install git-filter-repo git filter-repo --strip-blobs-bigger-than 25M # or by path: git filter-repo --path assets/huge.psd --invert-pathsEvery hash after the affected commits changes. Teammates must re-clone, not pull.
Reclaim the space and prevent a repeat
Garbage collection is what actually frees the disk. Then set up LFS so large binaries never enter history again.
step 5git reflog expire --expire=now --all git gc --prune=now --aggressive git count-objects -vH git lfs install git lfs track "*.psd" "*.fbx" "*.wav" git add .gitattributes
Why this works
Git keeps every version of every file forever, and binaries barely compress and change wholesale on each save, so a handful of large assets can dwarf years of source code. Deleting a file adds a commit in which it's absent, but every earlier commit still contains it and a clone downloads all of them. Only rewriting those commits removes the blob, and only garbage collection then reclaims the disk. LFS sidesteps the whole problem by storing a small pointer in Git and the payload elsewhere.
How to stop it happening again
- Set up Git LFS before committing binary assets, not after.
- Ignore build output and caches - for Unity that means Library/, Temp/, Build/ and Logs/.
- Add a pre-commit hook rejecting files over a size threshold.
- Check git count-objects -vH occasionally so bloat is caught early.
Commands used in this guide
git count-objectsReport how much disk space the repository is using.
git rev-listList commit hashes matching a range or filter - the engine behind git log.
git cat-filePrint the raw contents or type of any object by its hash.
git filter-repoRewrite an entire repository's history - the supported way to purge a leaked secret or a huge file.
git lfsStore large binary files outside history and keep the repo small.
git gcCompress the repository and delete unreachable objects.
Still stuck?
Search the full command reference and every other rescue guide — there are 56 of them, covering everything from detached HEAD to force-push disasters.
Browse all guides →Frequently asked questions
How do I find the largest files in Git history?
Pipe git rev-list --objects --all into git cat-file --batch-check to get each object's type, size and path, filter to blobs, then sort by size. The largest entries are what's inflating your repository, whether or not they still exist in the working tree.
Why is my repo still huge after deleting the big file?
Because deletion only adds a commit where the file is absent. Every earlier commit still contains it, and clones fetch all history. The blob is only gone once you rewrite those commits with filter-repo and run garbage collection.
What size is too big for a Git repository?
There's no hard limit, but clones slow noticeably past about 1 GB and become painful past a few gigabytes. GitHub warns above 1 GB and rejects any single file over 100 MB. Anything binary and over a few megabytes belongs in LFS.
Related rescue guides
I committed a large file and my push is rejected — how do I remove it?
If it's still the last commit, git reset --soft HEAD~1 and re-commit without it. If it's further back, purge it from history with git filter-repo --strip-blobs-bigger-than. Going forward, route large binaries through Git LFS.
Read the fix →Usually recoverableGit says 'object file is empty' or 'loose object is corrupt' — can I repair it?
Corruption is almost always a few damaged object files after a crash, disk problem or a killed process. Run git fsck to identify them, delete the empty or unreadable ones, and re-fetch the good copies from your remote. If you have a remote, a fresh clone is often the fastest fix.
Read the fix →Always fixableCloning takes forever — how do I clone a big repo faster?
Use --filter=blob:none for a partial clone that fetches file contents lazily, and add sparse-checkout to materialise only the directories you need. --depth 1 is fastest of all but gives you no usable history.
Read the fix →Always fixableHow do I extract a folder from my repo into a separate repo with its history?
git filter-repo --path <dir> --path-rename <dir>/: keeps only that directory and moves it to the root, preserving every commit that touched it. Work on a fresh clone so your original repository is never at risk.
Read the fix →