When Is Non-Cone Mode Required for Sparse Checkout in actions/checkout
Set sparse-checkout-cone-mode: false when you need to checkout individual files, use glob-style or negative patterns, exclude the repository root from the working tree, or support Git versions older than 2.25.
The actions/checkout action supports sparse checkout to clone only specific portions of a repository, reducing bandwidth and storage overhead. While the default cone mode efficiently handles directory prefixes, certain advanced filtering scenarios require disabling it to use the classic implementation that accepts arbitrary path patterns.
Understanding Cone Mode vs Non-Cone Mode
actions/checkout implements two distinct sparse checkout algorithms:
- Cone mode (default): Uses the Git 2.25+ "cone-mode" algorithm. It only accepts directory prefixes (e.g.,
src/,docs/). This mode is optimized for performance and simplicity. - Non-cone (classic) mode: Falls back to the older
core.sparseCheckoutimplementation. It accepts arbitrary path patterns, including single files, glob-style patterns, and negative patterns.
The action determines which mode to use via the sparse-checkout-cone-mode input, which defaults to true.
When Non-Cone Mode Is Required
You must explicitly set sparse-checkout-cone-mode: false in the following scenarios:
Checking Out Individual Files
Cone mode strictly requires directory prefixes. If your workflow needs to fetch only specific files—such as README.md or LICENSE—without their parent directories, non-cone mode is mandatory.
In src/git-source-provider.ts, the action branches based on this flag:
if (settings.sparseCheckoutConeMode) {
await git.sparseCheckout(settings.sparseCheckout)
} else {
await git.sparseCheckoutNonConeMode(settings.sparseCheckout)
}
(Source: src/git-source-provider.ts, lines 61-65)
Complex Pattern Matching
Non-cone mode supports advanced pattern syntax that cone mode rejects:
- Glob patterns: Wildcards like
src/**/*.test.ts - Negative patterns: Exclusions like
!docs/internal/
These patterns rely on the classic core.sparseCheckout configuration rather than the cone algorithm's simplified prefix matching.
Excluding the Repository Root
If you require a working tree where the repository root directory remains empty except for explicitly listed paths, non-cone mode is required. The test suite in __test__/verify-sparse-checkout-non-cone-mode.sh validates this behavior, verifying that root files do not exist when non-cone mode is active:
ENABLED=$(git config --local --get-all core.sparseCheckout)
if [ "$ENABLED" != "true" ]; then
echo "Expected sparse-checkout to be enabled (is: $ENABLED)"
exit 1
fi
# ... verify listed directories exist, root files do NOT exist ...
(Source: __test__/verify-sparse-checkout-non-cone-mode.sh, lines 12-23)
Legacy Git Compatibility
Cone mode requires Git 2.25 or later. Workflows running on self-hosted runners with older Git installations must use non-cone mode to perform any sparse checkout.
How the Action Determines the Mode
The flag parsing occurs in src/input-helper.ts:
result.sparseCheckoutConeMode =
(core.getInput('sparse-checkout-cone-mode') || 'true').toUpperCase() === 'TRUE'
(Source: src/input-helper.ts, lines 118-120)
When sparseCheckoutConeMode is false, the action invokes git.sparseCheckoutNonConeMode() from src/git-command-manager.ts, configuring core.sparseCheckout to true and writing patterns directly to .git/info/sparse-checkout without the cone algorithm's restrictions.
Configuration Examples
Sparse Checkout of a Single File
This example checks out only README.md, leaving the root folder otherwise empty:
steps:
- uses: actions/checkout@v7
with:
sparse-checkout: |
README.md
sparse-checkout-cone-mode: false
Result: Only README.md is present in the working directory.
Mixed Directories and Files
To checkout both directories and individual files simultaneously:
steps:
- uses: actions/checkout@v7
with:
sparse-checkout: |
src
docs
LICENSE
sparse-checkout-cone-mode: false
Result: The src/ and docs/ directories are fully checked out, plus the LICENSE file. Non-prefix patterns (the file) are allowed only in non-cone mode.
Default Cone Mode for Directory Prefixes
For comparison, the default cone mode works efficiently with directory-only patterns:
steps:
- uses: actions/checkout@v7
with:
sparse-checkout: |
src
docs
Result: Fast checkout of the two directories. Any non-directory pattern would be rejected or behave unpredictably.
Summary
- Cone mode (default) accepts only directory prefixes and requires Git 2.25+—use it for simple folder-based sparse checkouts.
- Non-cone mode is required for individual files, glob patterns, negative patterns, or excluding the repository root.
- Set
sparse-checkout-cone-mode: falseto enable the classiccore.sparseCheckoutimplementation. - The action implements this logic in
src/git-source-provider.tsandsrc/git-command-manager.ts, with input parsing handled insrc/input-helper.ts.
Frequently Asked Questions
Can I use glob patterns like **/*.md in sparse checkout?
Yes, but only in non-cone mode. Cone mode strictly interprets sparse checkout patterns as directory prefixes. To use glob patterns, wildcards, or file-level filtering, you must set sparse-checkout-cone-mode: false according to the actions/checkout source code implementation.
Why is single file checkout failing with cone mode enabled?
Cone mode only recognizes directory paths, not individual files. When you specify a file path like README.md with the default sparse-checkout-cone-mode: true, Git treats it as a directory prefix that doesn't exist. Disable cone mode to checkout specific files.
Does non-cone mode work with all Git versions?
Non-cone mode has broader compatibility than cone mode. While cone mode requires Git 2.25 or later, the classic core.sparseCheckout implementation used in non-cone mode works with significantly older Git versions, making it necessary for legacy self-hosted runner environments.
How can I verify that non-cone mode is working correctly?
The action's test suite uses __test__/verify-sparse-checkout-non-cone-mode.sh to validate behavior. You can verify manually by checking that git config --local --get-all core.sparseCheckout returns true and confirming that root files are absent while only your specified paths are present in the working tree.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →