Large Repos
Everything in this series so far assumes a repository of a size where git clone just works in a few seconds and nobody thinks about it. Past a certain size — large binary assets, years of deep history, or a single repo containing many independent projects — that assumption breaks down, and git offers specific tools for each distinct problem.
Identifying Which Large-Repo Problem You Actually Have
Git LFS — Large File Storage
Git LFS replaces large files in your repo with small text pointers, while the actual file content lives in separate LFS storage — git's normal history-tracking machinery (Chapter 1's object model) only ever sees the lightweight pointer, not the heavy binary itself.
$ git lfs install
$ # Tell LFS which file types to track (writes to .gitattributes)
$ git lfs track "*.mp4"
$ git lfs track "*.psd"
$ # From here, normal git commands just work
$ git add .gitattributes video.mp4
$ git commit -m "Add product demo video"
$ git push
git lfs migrate) — every previous commit's full-size version is still sitting in the regular object database otherwise. Setting up .gitattributes at the start of a project, before the first large file is ever committed, avoids this entirely.
Shallow Clones — Downloading Only Recent History
$ git clone --depth 1 https://github.com/big-org/huge-project.git
$ # Or the last 50 commits, if you need a bit more context
$ git clone --depth 50 https://github.com/big-org/huge-project.git
A shallow clone is dramatically faster for repos with years of history — most CI systems (Course 2/3's Actions chapters) use shallow clones by default, since a workflow run usually only needs the current state, not the full history.
git fetch --unshallow converts it to a full clone if you later find you need that history after all.
Sparse Checkout — Downloading Only Part of the Tree
For a monorepo where the full history is needed but only a fraction of the file tree is actually relevant to you, sparse checkout downloads everything's history but only checks out the specific folders you choose into your working directory.
$ cd monorepo
$ git sparse-checkout set frontend/web-app shared/ui-components
/* only these two folders now appear in your working directory */
The --filter=blob:none flag avoids downloading file contents you haven't checked out yet, fetching them lazily only when actually needed — a meaningful speed difference on a genuinely large monorepo.
Monorepo Strategy — A Brief Orientation
A monorepo holds multiple, often-independent projects in a single repository, rather than splitting each into its own repo (the more traditional approach, and what every previous chapter implicitly assumes).
- Advantages: atomic cross-project changes in a single commit/PR, shared tooling and CI config, easier code sharing between projects without the submodule/subtree complexity from Chapter 4.
- Trade-offs: repo size and clone time grow with every project added (exactly what this chapter's tools mitigate), and CI needs to be smart enough to only test/build what actually changed rather than the entire repo on every push.
- Tooling matters more at scale. Beyond a certain size, dedicated monorepo tools (Nx, Turborepo, Bazel) handle the "only build what changed" problem far better than hand-rolled CI logic — worth researching directly if a monorepo grows large enough that this chapter's git-level tools alone aren't enough.
Command Reference
| Command | What it does |
|---|---|
| git lfs install | One-time setup enabling LFS on a machine |
| git lfs track "*.ext" | Marks a file pattern to be stored via LFS, written to .gitattributes |
| git clone --depth N | Shallow clone — only the last N commits of history |
| git fetch --unshallow | Converts a shallow clone into a full one |
| git clone --filter=blob:none --sparse | Clones with full history but no file content yet, ready for sparse checkout |
| git sparse-checkout set <paths> | Chooses which folders actually appear in the working directory |
Chapter 7 Quick Reference
- Git LFS — for large binary files; stores a lightweight pointer in git, real content in separate LFS storage
- Set up LFS tracking before committing large files where possible — converting after the fact needs a history rewrite
- Shallow clone (--depth N) — for deep history you don't need; common default for CI runners
- Some operations (bisect, old-commit inspection) need full history — git fetch --unshallow if needed later
- Sparse checkout — for a huge file tree (monorepo); full history, only checked-out folders you actually need
- Monorepo trade-off: easier cross-project changes and sharing, vs. growing repo size and CI complexity
- Most projects never need this chapter's tools — reach for them when a real, measured scale problem appears
- Next chapter: git bisect — finding exactly which commit introduced a regression