# How Sparse Checkout Works Internally in actions/checkout

> Discover how sparse checkout works internally in actions/checkout. Learn about Git version checks, partial clones with blob none, and cone vs legacy modes for efficient Git operations.

- Repository: [GitHub Actions/checkout](https://github.com/actions/checkout)
- Tags: internals
- Published: 2026-07-16

---

**The actions/checkout action implements sparse checkout by parsing the `sparse-checkout` input into path patterns, validating Git version 2.28+, fetching with `--filter=blob:none` for partial clones, and executing either `git sparse-checkout set` for cone mode or manually writing patterns to `.git/info/sparse-checkout` for legacy non-cone mode.**

The `actions/checkout` GitHub Action supports sparse checkout to reduce repository size and clone time by fetching only specific directories. This feature leverages Git's native sparse-checkout capabilities according to the source code in the `actions/checkout` repository. Internally, the action orchestrates a series of Git commands across multiple TypeScript modules to configure the repository before the final checkout operation.

## Input Parsing and Settings Configuration

The sparse checkout process begins in [`src/input-helper.ts`](https://github.com/actions/checkout/blob/main/src/input-helper.ts), where the action reads the multiline `sparse-checkout` input and the optional `sparse-checkout-cone-mode` flag. The multiline input splits on line breaks, with each line becoming a path pattern stored in the settings object.

```typescript
const sparseCheckout = core.getMultilineInput('sparse-checkout')
if (sparseCheckout.length) {
  result.sparseCheckout = sparseCheckout
}
result.sparseCheckoutConeMode =
  (core.getInput('sparse-checkout-cone-mode') || 'true').toUpperCase() === 'TRUE'

```

These values populate the `IGitSourceSettings` interface defined in [`src/git-source-settings.ts`](https://github.com/actions/checkout/blob/main/src/git-source-settings.ts), which includes `sparseCheckout: string[]` and `sparseCheckoutConeMode: boolean`. This configuration object passes downstream to the source provider.

## Git Version Validation

Before executing sparse checkout commands, the action validates the Git version in [`src/git-command-manager.ts`](https://github.com/actions/checkout/blob/main/src/git-command-manager.ts). The `MinimumGitSparseCheckoutVersion` constant requires Git 2.28 or later.

```typescript
if (this.doSparseCheckout) {
  if (!this.gitVersion.checkMinimum(MinimumGitSparseCheckoutVersion)) {
    throw new Error(
      `Minimum Git version required for sparse checkout is ${MinimumGitSparseCheckoutVersion}`
    )
  }
}

```

If the runner's Git version is older than 2.28, the action aborts with a clear error message preventing incompatible operations.

## Partial Clone Optimization

When sparse checkout is enabled, the fetch operation in [`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts) adds `--filter=blob:none` to create a partial clone. This optimization ensures Git only pulls tree objects initially, leaving actual file blobs to be fetched lazily when accessed.

```typescript
if (settings.sparseCheckout) {
  fetchOptions.filter = 'blob:none'
}
await git.fetch(refSpec, fetchOptions)

```

This approach significantly reduces initial clone size and network transfer for large repositories.

## Cone Mode vs Non-Cone Mode Implementation

The [`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts) file determines which sparse checkout strategy to apply based on the `sparseCheckoutConeMode` setting. The action supports three distinct paths:

**No Sparse Checkout** → Calls `git.disableSparseCheckout()` to clear any previous configuration.

**Cone Mode** (`sparse-checkout-cone-mode: true`) → Invokes `git.sparseCheckout(patterns)` which executes:

```typescript
async sparseCheckout(sparseCheckout: string[]): Promise<void> {
  await this.execGit(['sparse-checkout', 'set', ...sparseCheckout])
}

```

Git 2.28+ supports the cone algorithm, which is faster and automatically expands directory patterns.

**Non-Cone Mode** (`sparse-checkout-cone-mode: false`) → Invokes `git.sparseCheckoutNonConeMode(patterns)` which manually configures the sparse-checkout file:

```typescript
async sparseCheckoutNonConeMode(sparseCheckout: string[]): Promise<void> {
  await this.execGit(['config', 'core.sparseCheckout', 'true'])
  const output = await this.execGit(['rev-parse','--git-path','info/sparse-checkout'])
  const sparseCheckoutPath = path.join(this.workingDirectory, output.stdout.trimRight())
  await fs.promises.appendFile(
    sparseCheckoutPath,
    `\n${sparseCheckout.join('\n')}\n`
  )
}

```

This legacy method writes patterns directly to `.git/info/sparse-checkout` and enables the `core.sparseCheckout` config flag, supporting older Git versions that predate the `sparse-checkout` subcommand.

## Disabling Sparse Checkout

When the `sparse-checkout` input is omitted, the action ensures a clean state by calling `disableSparseCheckout()` in [`src/git-command-manager.ts`](https://github.com/actions/checkout/blob/main/src/git-command-manager.ts):

```typescript
async disableSparseCheckout(): Promise<void> {
  await this.execGit(['sparse-checkout', 'disable'])
  await this.tryConfigUnset('extensions.worktreeConfig', false)
}

```

This removes any existing sparse-checkout configuration and cleans up worktree extensions.

## Verification and Testing

The implementation is guarded by shell scripts in the `__test__/` directory. The [`verify-sparse-checkout.sh`](https://github.com/actions/checkout/blob/main/verify-sparse-checkout.sh) script validates that the sparse-checkout list is non-empty, that all listed directories exist, and that only requested directories populate the working tree. Similarly, [`verify-sparse-checkout-non-cone-mode.sh`](https://github.com/actions/checkout/blob/main/verify-sparse-checkout-non-cone-mode.sh) verifies correct behavior when cone mode is disabled.

## Practical Configuration Examples

### Basic Sparse Checkout (Cone Mode)

```yaml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          sparse-checkout: |
            src/
            docs/
            .github/

```

This configuration populates only the `src/`, `docs/`, and `.github/` directories, leaving the rest as a partial clone.

### Non-Cone Mode (Legacy)

```yaml
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          sparse-checkout: |
            lib/
            test/
          sparse-checkout-cone-mode: false

```

This forces file-based sparse checkout by writing patterns to `.git/info/sparse-checkout` and setting `core.sparseCheckout=true`.

### Combined with Shallow Fetch

```yaml
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 1
          sparse-checkout: |
            .github/
            .eslintrc.js

```

The fetch step uses `--filter=blob:none` alongside shallow cloning to minimize repository size.

## Summary

- **Input parsing** in [`src/input-helper.ts`](https://github.com/actions/checkout/blob/main/src/input-helper.ts) extracts path patterns from the multiline `sparse-checkout` input and determines cone mode preference.
- **Version validation** ensures Git 2.28+ is installed before attempting sparse checkout operations.
- **Partial clone optimization** uses `--filter=blob:none` during fetch to defer blob downloads until actually needed.
- **Cone mode** executes `git sparse-checkout set` for efficient directory-based filtering.
- **Non-cone mode** manually writes to `.git/info/sparse-checkout` for legacy compatibility.
- **Cleanup** via `disableSparseCheckout()` clears configurations when sparse checkout is not requested.

## Frequently Asked Questions

### What is the minimum Git version required for sparse checkout in actions/checkout?

Git version 2.28 is the minimum required version. The action checks this via `MinimumGitSparseCheckoutVersion` in [`src/git-command-manager.ts`](https://github.com/actions/checkout/blob/main/src/git-command-manager.ts) and throws an error if the runner's Git version is insufficient.

### What is the difference between cone mode and non-cone mode in sparse checkout?

**Cone mode** (default) uses `git sparse-checkout set` and implements an algorithm that automatically expands directory patterns, offering better performance for typical directory-based filtering. **Non-cone mode** manually writes patterns to `.git/info/sparse-checkout` and sets `core.sparseCheckout=true`, supporting legacy Git versions and complex pattern matching but with slower performance.

### How does actions/checkout optimize fetch performance when using sparse checkout?

The action automatically adds `--filter=blob:none` to the fetch command when sparse checkout is enabled. This creates a partial clone where only tree objects are fetched initially, and file blobs are downloaded on-demand when accessed, significantly reducing initial clone time and storage.

### Can sparse checkout be combined with shallow cloning?

Yes. You can combine `sparse-checkout` with `fetch-depth: 1` (or any shallow depth) to create a minimal repository footprint. The action will apply both optimizations: shallow history via `--depth` and partial file retrieval via `--filter=blob:none`.