Clean up historyAlways fixable

Remove a huge file that's bloating your repository

I committed a large file and my push is rejected — how do I remove it?

Short answer

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.

quick fix
git reset --soft HEAD~1
git restore --staged path/to/huge-file.psd
git commit -m "Commit without the large asset"

Fixes it when the large file is in the most recent commit

Does this match your situation?

  • GitHub rejects your push: 'file exceeds GitHub's file size limit of 100 MB'.
  • Cloning the repository takes an extremely long time.
  • A .psd, .fbx, video, database dump or build artifact got committed.
  • The .git folder is enormous compared to your actual project.

Step-by-step fix

  1. Find what's actually taking up the space

    Before rewriting anything, confirm which objects are the problem. This lists the largest blobs in your history by size.

    step 1
    git count-objects -vH
    
    git rev-list --objects --all |
      git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' |
      awk '/^blob/ {print $3, $4}' |
      sort -rn |
      head -10
    
    Show the PowerShell (Windows) version
    PowerShell (Windows)
    git count-objects -vH
    git verify-pack -v .git/objects/pack/*.idx |
      Sort-Object { [int]($_ -split '\s+')[2] } -Descending |
      Select-Object -First 10
    
  2. If it's in the last commit, just redo it

    By far the easiest case. Undo the commit, drop the offending file from the staging area, and commit again without it.

    step 2
    git reset --soft HEAD~1
    git restore --staged assets/huge-texture.psd
    echo "*.psd" >> .gitignore
    git add .gitignore
    git commit -m "Add textures, excluding source PSD files"
    
  3. If it's deeper in history, purge it

    A file committed and then deleted still lives in every earlier commit and still gets cloned. Removing it properly means rewriting those commits. Clone a backup first.

    step 3
    git clone --mirror . ../repo-backup.git
    
    pip install git-filter-repo
    
    # remove one path from all of history:
    git filter-repo --path assets/huge-texture.psd --invert-paths
    
    # or strip everything over 50 MB:
    git filter-repo --strip-blobs-bigger-than 50M
    
  4. Force-push and have the team re-clone

    The rewrite changed every affected commit hash, so the remote needs the new history and existing clones are stale.

    step 4
    git remote add origin <url>       # filter-repo drops remotes deliberately
    git push --force --all
    git push --force --tags
    

    Teammates must re-clone. Pulling would drag the large objects straight back in.

  5. Set up Git LFS so it doesn't recur

    LFS keeps large binaries on a separate store and commits only a small pointer file, which is the correct long-term answer for art, audio and 3D assets.

    step 5
    git lfs install
    git lfs track "*.psd"
    git lfs track "*.fbx"
    git lfs track "*.wav"
    git add .gitattributes
    git commit -m "Track binary assets with Git LFS"
    

Why this works

Git stores a complete compressed copy of every version of every file, forever. That's ideal for text, where each revision compresses down to a small delta, and terrible for binaries, which barely compress and change wholesale every save. Deleting the file in a later commit doesn't help, because clones fetch all history by default and the old objects come along. Only rewriting the commits that contained the blob actually removes it — and LFS avoids the problem entirely by storing a 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 imported caches — for Unity that means Library/, Temp/, Build/ and Logs/.
  • Add a pre-commit hook that rejects files over a size threshold.
  • Run git count-objects -vH occasionally to catch bloat early.

Commands used in this guide

git filter-repo

Rewrite an entire repository's history - the supported way to purge a leaked secret or a huge file.

git lfs

Store large binary files outside history and keep the repo small.

git reset

Move the current branch pointer, optionally rewriting the index and your files.

git restore

Throw away working-directory changes or unstage files (the modern, clearer replacement for checkout).

git push

Upload your commits to the remote repository.

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 remove a large file from Git history?

Use git filter-repo --path <file> --invert-paths to strip it from every commit, or --strip-blobs-bigger-than 50M to remove everything over a size threshold. Then force-push, and have everyone re-clone rather than pull.

Why is my repository still huge after deleting the file?

Because deleting a file only adds a commit where it's absent — every earlier commit still contains it, and clones download all history. The blob is only gone once you rewrite those commits and run garbage collection.

What is Git LFS and when should I use it?

Git Large File Storage replaces big binaries with small pointer files and keeps the real data on a separate server. Use it for art, audio, video, 3D models and any asset over a few megabytes — and set it up before those files are committed, since retrofitting means rewriting history.

GitHub rejected my push for a file over 100 MB — what now?

GitHub blocks any single file over 100 MB regardless of your repo size. Remove the file from the commits that contain it (reset if it's the latest, filter-repo if it's older), then either exclude it or track it with Git LFS before pushing again.

Related rescue guides

← All Git Rescue guides