Measuring the real cost of clone options
Choosing the right git clone strategy is about more than download speed. Each option changes how the client and server behave on later operations like git fetch, and the tradeoffs shift depending on repository size and workload. To pin down those differences, GitHub’s engineering team ran a controlled experiment across three open source repositories, measuring client time, server CPU, and the effects of subsequent fetches.
The test repositories—jquery/jquery (40MB), apple/swift (750MB), and torvalds/linux (4GB)—were mirrored to a GitHub Enterprise Server 2.22 instance on an 8-core cloud machine. Load was generated with an internal Gatling-based tool across five generators running Git 2.28.0 for 30 minutes per scenario, with each repository also receiving ongoing commits from a separate writer to ensure fetches had new data to retrieve. Results were correlated with ghe-governor and server health metrics.
Scenarios and methodology
The experiment covered four clone types:
- Full clones
- Shallow clones (
--depth=1) - Treeless partial clones (
--filter=tree:0) - Blobless partial clones (
--filter=blob:none)
Those were paired with fetch strategies that make sense for each clone type. Shallow fetches (--depth=1) were tested against full and shallow clones—since treeless and blobless clones already limit object transfer during fetch, they weren’t combined with shallow fetches. Ten scenarios (T1–T10) were defined: T1–T4 measured a single clone per type; T5–T10 added a new commit and then ran a git fetch followed by git reset --hard origin/$branch. The reset step matters for partial clones because blobs at the new ref tip are only downloaded when populating the working directory. In all scenarios, a single user repeatedly modified three random files and pushed to the same branch, simulating repository growth so fetch operations had real data to pull.
The clone results
As expected, clone speed scaled inversely with the amount of data required. Shallow clones were fastest on the client, followed by treeless, then blobless, then full clones. The gap widens as the repository grows: for torvalds/linux, the shallow clone was about four times faster than a full clone, while treeless was roughly twice as fast and blobless only 1.5 times faster. Notably, the Linux repository’s typically small, highly compressible blobs may understate the advantage partial clones offer on repositories with heavier blob loads.
Server behavior tells a different story. For larger repositories, partial clones (T3 and T4) consumed more Git CPU time per clone than full clones, largely driven by pack-objects. For torvalds/linux, treeless cloning used four times more pack-objects CPU than a full clone. This is because full clones can largely stream the on-disk pack data directly, while partial and shallow clones must extract subsets and repackage them. The smaller jquery/jquery repository actually showed full clones consuming more total and Git CPU than partial clones, and shallow clones were the cheapest on the server across all three repositories. The GitHub team noted they are actively investigating ways to cut this CPU overhead in partial clones.
Fetch performance: where strategies diverge
The most significant finding concerns shallow fetches. Fetching with --depth=1 into a previously completed clone—particularly a full clone—proved to be the worst option tested. A shallow boundary disables a key server-side optimization that counts reachable objects, forcing the server to walk commits and trees from the client’s perspective. The cost grows with client history, since more commits and trees must be examined to avoid duplication, and the client must also send incremental data describing accumulated shallow boundaries.
Partial clones also diverge sharply in post-clone workflows:
- Blobless partial clones: Fetching plus a hard reset adds a small, measurable amount of time versus a full clone. The full commit history remains available, and network transfer is still substantially below full or shallow fetch patterns. These work well for interactive use on large repositories.
- Treeless partial clones: The reset operation is dramatically slower. Since the server must supply every tree and blob reachable from the commit’s root tree to reconstruct the working directory, any access to files incurs considerable cost that grows with repository size. The GitHub team strongly advises against relying on treeless clones beyond one-shot use cases—like a build machine that needs history but will discard the checkout immediately.
Blobless partial clones do push somewhat more Git CPU onto the server, but that is likely to be a worthwhile tradeoff for repositories whose blobs are larger than those in the test set. The team also flagged that blobless clones may trigger automatic garbage collection more frequently as a side effect of many small object requests; work is underway to make repository maintenance more flexible for large repositories where a full repack is prohibitive.
During the heavier treeless and blobless tests on the Linux repository, the load generators ran into memory pressure from concurrent background garbage collection processes. The synthetic load triggered GC more aggressively than real usage would, so git config gc.auto false was applied to keep the experiment focused on fetch behavior.
What this means in practice
If you are picking a clone strategy, the tradeoffs shake out like this:
- Full clones offer the simplest post-clone experience and the least server CPU at clone time, but cost the most network bandwidth. They remain a perfectly reasonable default for smaller repositories.
- Shallow clones are ideal for quick, throwaway checkouts. Avoid making them the base for incremental fetching—the shallow boundary makes future fetches far more expensive for the server.
- Treeless partial clones are only recommended when you need full history quickly without blob data and will not retain the repository. Repeated fetches and resets into a treeless clone become progressively slower.
- Blobless partial clones provide the best balance for large, active repositories when you need history and are willing to pay incremental fetch costs. The added server CPU is generally outweighed by large bandwidth savings.
- Shallow fetches into any persistent clone—especially a full one—should be avoided; they disable key server optimizations and get slower as history accumulates.
The measured behavior depends on repository shape, workflow, and load, so results will vary in your environment. GitHub’s controlled simulations do not reproduce the breadth of real-world usage patterns. The methodology itself—measuring clone and fetch behavior separately, tracking server CPU with governor metrics, and loading with Gatling—provides a template for evaluating these options against your own repository and usage profile.
Detailed results
Full numbers for clone and fetch performance are provided below. Scenario references: T1 is full clone, T2 is shallow clone (--depth=1), T3 is treeless partial clone, T4 is blobless partial clone, T5–T8 are the same clone types followed by a full or shallow fetch, and T9–T10 are fetches into blobless and treeless partial clones respectively.
Repository characteristics
Repo
blobs
trees
commits
Size (MB)
jquery/jquery14,779
22,579
7,873
40
apple/swift390,116
649,322
132,316
750
torvalds/linux2,174,798
4,619,864
968,500
4,000
Scenario definitions
Test#
git command
Description
T1
git cloneFull clone
T2
git clone --depth 1Shallow clone
T3
git clone --filter=tree:0Treeless partial clone
T4
git clone --filter=blob:noneBlobless partial clone
T5
T1 +
git fetchFull fetch in a fully cloned repository
T6
T1 +
git fetch --depth 1Shallow fetch in a fully cloned repository
T7
T2 +
git fetchFull fetch in a shallow cloned repository
T8
T2 +
git fetch --depth 1Shallow fetch in a shallow cloned repository
T9
T3 +
git fetchFull fetch in a treeless partially cloned repository
T10
T4 +
git fetchFull fetch in a blobless partially cloned repository
Clone performance by repository
Test#
description
clone avgRT (milliseconds)
git CPU spent per clone
T1
full clone
2,000ms (Slowest)
450ms (Highest)
T2
shallow clone
300ms (6x faster than T1)
15ms (30x less than T1)
T3
treeless partial clone
900ms (2.5x faster than T1)
270ms (1.7x less than T1)
T4
blobless partial clone
900ms (2.5x faster than T1)
300ms (1.5x less than T1)
Test#
description
clone avgRT (seconds)
git CPU spent per clone
T1
full clone
50s (Slowest)
8s (2x less than T4)
T2
shallow clone
8s (6x faster than T1)
3s (6x less than T4)
T3
treeless partial clone
16s (3x faster than T1)
13s (Similar to T4)
T4
blobless partial clone
22s (2x faster than T1)
15s (Highest)
Test#
description
clone avgRT (minutes)
git CPU spent per clone
T1
full clone
5m (Slowest)
60s (2x less than T4)
T2
shallow clone
1.2m (4x faster than T1)
40s (3.5x less than T4)
T3
treeless partial clone
2.4m (2x faster than T1)
120s (Similar to T4)
T4
blobless partial clone
3m (1.5x faster than T1)
130s (Highest)
Fetch performance by repository
Test#
scenario
git fetch avgRT
git reset –hard
git CPU spent per fetch
T5
full fetch in a fully cloned repository
200ms
5ms
4ms (Lowest)
T6
shallow fetch in a fully cloned repository
300ms
5ms
18ms (4x more than to T5)
T7
full fetch in a shallow cloned repository
200ms
5ms
4ms (Similar to T5)
T8
shallow fetch in a shallow cloned repository
250ms
5ms
14ms (3x more than to T5)
T9
full fetch in a treeless partially cloned repository
200ms
85ms
9ms (2x more than to T5)
T10
full fetch in a blobless partially cloned repository
200ms
40ms
6ms (1.5x more than to T5)
Test#
scenario
git fetch avgRT
git reset –hard
git CPU spent per fetch
T5
full fetch in a fully cloned repository
350ms
80ms
20ms (Lowest)
T6
shallow fetch in a fully cloned repository
1,500ms
80ms
300ms (13x more than to T5)
T7
full fetch in a shallow cloned repository
300ms
80ms
20ms (Similar to T5)
T8
shallow fetch in a shallow cloned repository
350ms
80ms
45ms (2x more than to T5)
T9
full fetch in a treeless partially cloned repository
300ms
300ms
70ms (3x more than to T5)
T10
full fetch in a blobless partially cloned repository
300ms
150ms
35ms (1.5x more than to T5)
Test#
scenario
git fetch avgRT
git reset –hard
git CPU spent per fetch
T5
full fetch in a fully cloned repository
350ms
250ms
40ms (Lowest)
T6
shallow fetch in a fully cloned repository
6,000ms
250ms
1,000ms (25x more than T5)
T7
full fetch in a shallow cloned repository
300ms
250ms
50ms (1.3x more than T5)
T8
shallow fetch in a shallow cloned repository
400ms
250ms
80ms (2x more than to T5)
T9
full fetch in a treeless partially cloned repository
350ms
1250ms
400ms (10x more than to T5)
T10
full fetch in a blobless partially cloned repository
300ms
500ms
140ms (3.5x more than to T5)
Choosing the Right Clone Strategy
Our tests show measurable differences between clone and fetch modes, but real-world results depend heavily on your repository's structure. The synthetic workload we used won't match every project. Still, a few patterns emerged that can guide your choice.
For developers working in a single repository, a full clone followed by full fetches is the most reliable baseline. If large blobs dominate the repository and slow down your initial checkout, a blobless partial clone (with --filter=blob:none) can get you started faster. The catch: operations like git checkout and git blame may trigger on-demand blob downloads.
Shallow fetches consistently cost more to compute than full fetches. Whether your repository is fully or shallowly cloned, prefer a full fetch whenever you need to update it.
Ephemeral Workflows: CI and One-Off Builds
When you clone only to build and discard the repository—as in CI pipelines—shallow clones are the fastest route to a working directory at a specific commit. If your build needs more history than a single tip, consider a treeless partial clone (--filter=tree:0) instead. Note that on large projects such as torvalds/linux, this saves client time but shifts more load onto the Git server compared to a full clone.
Blobless partial clones pair particularly well with Git's sparse-checkout feature, cutting the number of blobs you handle dramatically. Sparse-checkout does not reduce data transfer for shallow clones, so don't combine those expecting a similar effect.
Our test repositories topped out at the size of torvalds/linux. Larger repositories—increasingly common in private settings—aren't well represented here. If yours falls into that category, replicating our experiments on your own data is the safest way to get actionable numbers.
Also keep in mind that this study uses a synthetic, homogeneous workload: it doesn't model branches, mixed user workflows, or the full range of commands in daily Git use. We continue to examine how these clone modes change the overall user experience.



