Skip to content

A git repository can be larger than the code it holds

History, packfiles and old branches accumulate in .git. How to find the heavy repositories, shrink them safely, and spot a large file in history.

6 min read

A checkout you can see is one copy of the code. The .git folder next to it holds every version of every file that repository has ever contained, which is why cloning something small can produce something large.

Find the heavy repositories

find ~ -type d -name .git -maxdepth 6 2>/dev/null \
  -exec du -sh {} + | sort -h | tail -20

That lists the twenty largest .git folders on the Mac. Compare each against the size of the project around it. A .git folder several times larger than the working tree means something heavy is in the history, and the next section finds it.

The routine cleanup first

git count-objects -vH
git gc --aggressive --prune=now

count-objects reports the split between loose objects and packed ones. gc repacks them and drops anything unreachable, which on a repository with a lot of branch churn can halve the folder. It is safe: nothing reachable from a branch, tag or the reflog is removed.

Note that --prune=now also discards the reflog's protection for commits you have already abandoned, so if you are in the middle of recovering a lost commit, do that first.

When the history itself is the problem

If gc barely moves the number, something large is committed in the history: a video, a dataset, a build artefact, or a dependency folder that should have been ignored. This lists the largest objects in the repository:

git rev-list --objects --all \
  | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \
  | awk '$1=="blob" {print $3, $4}' | sort -n | tail -20

Removing a file from history rewrites every commit that touched it, which changes commit hashes and requires a force push and a fresh clone for everyone else. On a shared repository that is a coordination problem rather than a technical one, and it is usually not worth doing for disk space alone.

The cheaper options

  • Delete the clone. For a repository you can clone again, the local copy is disposable. This is the fastest gigabytes on any developer Mac.
  • Clone shallow next time. git clone --depth 1 fetches one commit of history instead of all of it.
  • Check Git LFS storage. LFS keeps its own cache under .git/lfs, and it holds versions of large files you no longer have checked out.
  • Remove build output, not history. Often the repository is fine and the target, build or node_modules folder beside it is what is large.
du -sh .git/lfs 2>/dev/null
git lfs prune

That last command removes local LFS files that are not needed by the current checkout, and it is usually the largest safe win on a repository that uses LFS. For the folders beside the repository rather than inside it, node_modules across every project and Rust target folders are the usual suspects.

Common questions

Why is my .git folder so large?

Because it stores every version of every file the repository has ever contained. If it is much larger than the working tree, something heavy is in the history, typically a dataset, a video, or a dependency folder that was committed before being ignored.

Is git gc safe to run?

Yes. It repacks objects and removes ones nothing references, and anything reachable from a branch, tag or the reflog is kept. Using --prune=now additionally drops the reflog's protection for already abandoned commits, so avoid it mid recovery.

How do I find large files in git history?

List all objects with git rev-list --objects --all and check their sizes with git cat-file --batch-check, then sort. That prints the largest blobs with their paths, which is usually enough to identify what was committed by mistake.

Does deleting a local clone lose anything?

Only if the repository has no remote. Run git remote -v first. With a remote, the clone is disposable and re-cloning restores everything, which makes it one of the easiest ways to reclaim space on a developer Mac.

Read next