The shallow tradeoff
A shallow clone (--depth=N) downloads only the last N commits. Faster, smaller, but with caveats: many history-dependent operations become impossible or wrong. CI is the natural home for shallow clones, but only when you understand the limits.
Basic invocation
git clone --depth=1 https://example.com/repo.git
git clone --depth=50 --no-tags https://example.com/repo.git
git clone --shallow-since=2024-01-01 https://example.com/repo.git
git clone --shallow-exclude=v1.0.0 https://example.com/repo.git
Single-branch
Shallow clones default to --single-branch with --depth. To clone all branches shallowly:
git clone --depth=1 --no-single-branch https://example.com/repo.git
What breaks
git logstops at the shallow boundary.git blameassigns deeper changes to the boundary commit.git bisectcan only search inside the shallow window.git merge-basemay fail to find a base that is older than the shallow.git pushis fine, butgit fetchreturning history older than the shallow requires--unshallow.
Promoting later
git fetch --unshallow
git fetch --depth=1000 # extend the depth
git fetch --shallow-since=2023-01-01
CI patterns
For build-and-test only:
git clone --depth=1 --no-tags --filter=tree:0 \
--branch "$CI_COMMIT_REF_NAME" "$CI_REPOSITORY_URL" .
Combining --depth=1 with --filter is generally redundant — depth already cuts history — but pairing with sparse-checkout for path-scoped builds is potent.
When to avoid shallow
- Release builds that embed git describe — needs tags and history.
- SBOM/license scanners that walk authorship.
- Bisect or blame steps in CI.
- Merge-base computations against a long-lived base branch.
Common mistakes
Using --depth=1 in a release pipeline that runs git describe and printing v0.0.0-unknown. Treating --unshallow as fast — it pulls the rest of history, large on big repos. Forgetting --no-tags on shallow CI clones; tags can balloon the transfer.
Related
See "Partial clone: promise and promisor remotes" for an alternative trade-off.