# How actions/checkout Handles Repository Fetching and Authentication: A Technical Deep Dive

> Discover how actions/checkout handles repository fetching and authentication through Git operations, credential injection, and artifact cleanup for secure CI/CD workflows.

- Repository: [GitHub Actions/checkout](https://github.com/actions/checkout)
- Tags: deep-dive
- Published: 2026-08-29

---

**The `actions/checkout` GitHub Action clones repositories by orchestrating workspace preparation, temporary credential injection for HTTPS or SSH via [`git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/git-auth-helper.ts), ref resolution, and controlled `git fetch` operations, followed by mandatory cleanup of all authentication artifacts.**

The `actions/checkout` action is the standard mechanism for accessing repository code in GitHub Actions workflows. Understanding how it handles repository fetching and authentication is essential for securing CI/CD pipelines and optimizing performance. This article examines the actual TypeScript implementation in the official repository to reveal how the action manages credentials without leaking secrets, resolves references, and executes Git commands.

## Entry Point and Orchestration in git-source-provider.ts

The entire checkout process is coordinated by the `getSource()` function in **[`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts)** (lines 18-31, 42-51, 74-84, 146-175). This orchestrator initializes the Git workspace, configures authentication, determines which references to fetch, and manages optional features like LFS and submodules.

### The getSource Function Workflow

When the action runs, `getSource()` executes a strict sequence:

1. **Workspace Preparation**: Creates or cleans the target directory to ensure a pristine environment.
2. **Git Manager Initialization**: Instantiates a `GitCommandManager` to abstract low-level Git CLI operations.
3. **Authentication Setup**: Calls `authHelper.configureAuth()` to prepare HTTPS or SSH credentials without exposing them in process arguments.
4. **Ref Resolution**: Uses [`ref-helper.ts`](https://github.com/actions/checkout/blob/main/ref-helper.ts) to convert user inputs (branch names, tags, or PR numbers) into precise Git ref-specs.
5. **Fetch Execution**: Invokes `git.fetch()` with calculated options for depth, filters, and tags.
6. **Post-Fetch Operations**: Optionally initializes submodules, enables sparse checkout, or pulls LFS objects.
7. **Credential Cleanup**: Removes all temporary authentication files and config entries.

## Authentication Mechanisms in git-auth-helper.ts

All credential handling is encapsulated in the **`GitAuthHelper`** class within **[`src/git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts)**. This module ensures tokens and SSH keys never appear in shell history or process listings by writing sensitive data to temporary files under `RUNNER_TEMP` and referencing them via Git config includes.

### Token-Based HTTPS Authentication

When using the default GitHub token or a personal access token, the helper builds an HTTP `AUTHORIZATION: basic` header using the provided `authToken` (lines 55-65). Rather than passing the token via command line, the action:

- Stores the header in a temporary credentials config file under `RUNNER_TEMP`
- References this file via `includeIf.gitdir:` entries in the Git config (lines 260-285)
- Restricts the include pattern to the repository directory to prevent credential leakage to other processes

This approach ensures the token is automatically injected only for requests targeting the specific repository and any worktrees derived from it.

### SSH Key Authentication

For SSH-based authentication, the helper handles private keys through environment variables and temporary files:

- Writes the `sshKey` and optional known-hosts data to temporary files under `RUNNER_TEMP` (lines 55-66)
- Sets the `GIT_SSH_COMMAND` environment variable to invoke `ssh -i <keyfile>` (lines 101-119)
- Configures `core.sshCommand` in the Git config when `persistCredentials` is true, ensuring submodules can authenticate using the same key

### Global Authentication for Submodules

When `submodules: true` is specified, the action must authenticate recursive clone operations. The `configureGlobalAuth()` method (lines 128-149) writes the token or SSH settings into a temporary `HOME` directory with a custom global Git config. This isolated environment prevents credentials from persisting in the user's actual global Git configuration while allowing `git submodule update` to access private repositories.

## Resolving References with ref-helper.ts

Before fetching, the action must translate user inputs into Git ref-specs. The **[`src/ref-helper.ts`](https://github.com/actions/checkout/blob/main/src/ref-helper.ts)** module converts various reference types:

- **Branch names**: Expands to `+refs/heads/<branch>:refs/remotes/origin/<branch>`
- **Pull requests**: Creates `+<sha>:refs/remotes/pull/<id>` for PR refs
- **Tags**: When `fetchTags` is true, adds `+refs/tags/*:refs/tags/*` (lines 91-95)

After fetching, `refHelper.testRef()` validates that the fetched commit matches the expected SHA to prevent race conditions where a branch moves between resolution and fetch (lines 191-210 in [`git-source-provider.ts`](https://github.com/actions/checkout/blob/main/git-source-provider.ts)).

## Executing the Fetch in git-command-manager.ts

The actual network operation occurs in **[`src/git-command-manager.ts`](https://github.com/actions/checkout/blob/main/src/git-command-manager.ts)** via the `fetch()` method (lines 277-298). This method constructs the Git command with protocol optimizations and performance flags:

```typescript
const args = ['-c', 'protocol.version=2', 'fetch'];
if (options.fetchDepth && options.fetchDepth > 0) {
  args.push(`--depth=${options.fetchDepth}`);
}
if (options.filter) {
  args.push(`--filter=${options.filter}`);
}
await exec.exec('git', args.concat(refSpec));

```

### Shallow Fetch and Filter Options

The action supports several fetch optimizations controlled by `IGitSourceSettings`:

- **`fetchDepth`**: Implements shallow cloning (`--depth=1` by default) to reduce transfer size
- **`filter`**: Supports blob filtering (`blob:none`) for partial clones
- **`fetchTags`**: Conditionally includes the tag ref-spec based on user configuration

When shallow fetching is requested, the action validates the resulting commit to ensure the ref still points to the expected SHA, protecting against the "shallow clone race condition" where the remote advances after the fetch but before the checkout.

## Optional Post-Fetch Operations

After the initial fetch succeeds, [`git-source-provider.ts`](https://github.com/actions/checkout/blob/main/git-source-provider.ts) handles several optional features:

### Git LFS and Sparse Checkout

- **LFS**: Runs `git lfs install` followed by `git lfs fetch <ref>` (lines 69-72)
- **Sparse Checkout**: Configures cone-mode or non-cone-mode sparse checkout patterns by calling `git.sparseCheckout()` or `git.sparseCheckoutNonConeMode()` (lines 60-66), allowing users to materialize only specific directories

### Submodule Initialization

When submodules are enabled (lines 74-85), the action executes:
1. `git submodule sync` to update submodule URLs
2. `git submodule update` to fetch and checkout submodule content
3. Disables automatic garbage collection to prevent credential traces from being packed into `.git` objects

For persisted credentials, `authHelper.configureSubmoduleAuth()` (lines 151-164) writes `includeIf` entries mapping submodule paths to the shared credentials config file, supporting both host and container path formats.

## Security and Cleanup Procedures

Security relies on the guarantee that temporary credentials are removed after the job completes. The **`removeAuth()`** method (lines 332-425 in [`git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/git-auth-helper.ts)) deletes:

- SSH private key temporary files
- SSH known-hosts temporary files
- HTTP authorization header config files

Additionally, `removeGlobalConfig()` restores the original `HOME` environment variable, ensuring the temporary global Git config is no longer referenced by subsequent processes.

## Practical Configuration Examples

### Basic HTTPS Checkout with Shallow History

```yaml
steps:
  - uses: actions/checkout@v4
    with:
      fetch-depth: 1
      token: ${{ secrets.GITHUB_TOKEN }}

```

*Uses automatic token injection via temporary HTTP headers without persisting credentials.*

### Full History Checkout with LFS

```yaml
steps:
  - uses: actions/checkout@v4
    with:
      fetch-depth: 0
      lfs: true
      fetch-tags: true

```

*Fetches all history and tag objects, then downloads LFS content after the initial clone.*

### SSH Authentication with Submodule Support

```yaml
steps:
  - uses: actions/checkout@v4
    with:
      ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
      submodules: recursive
      persist-credentials: true

```

*Writes the SSH key to `RUNNER_TEMP`, sets `GIT_SSH_COMMAND`, and configures global SSH settings for nested submodules.*

### Sparse Checkout (Cone Mode)

```yaml
steps:
  - uses: actions/checkout@v4
    with:
      sparse-checkout: |
        src/
        docs/
      sparse-checkout-cone-mode: true

```

*Only materializes the `src` and `docs` directories, leaving other repository content unfetched.*

## Summary

- **Orchestration**: [`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts) coordinates the entire flow via `getSource()`, managing workspace preparation, authentication, fetching, and cleanup
- **Security**: [`src/git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts) prevents credential leakage by writing tokens and SSH keys to temporary files under `RUNNER_TEMP` and referencing them via Git config includes rather than command-line arguments
- **Ref Resolution**: [`src/ref-helper.ts`](https://github.com/actions/checkout/blob/main/src/ref-helper.ts) converts branches, tags, and PR numbers into precise Git ref-specs and validates fetched commits
- **Execution**: [`src/git-command-manager.ts`](https://github.com/actions/checkout/blob/main/src/git-command-manager.ts) executes `git fetch` with protocol version 2, shallow depth, and blob filters for optimized transfers
- **Cleanup**: All authentication artifacts are removed after checkout, including temporary SSH keys and HTTP header configs, unless `persist-credentials: true` is explicitly set for submodule operations

## Frequently Asked Questions

### How does actions/checkout authenticate with GitHub repositories?

By default, `actions/checkout` uses the automatic `GITHUB_TOKEN` provided by the workflow runner. The action writes this token to a temporary credentials file under `RUNNER_TEMP` and configures Git to include an `Authorization: basic` header only for requests targeting the specific repository directory via `includeIf.gitdir:` directives. This prevents the token from appearing in process listings or shell history while ensuring only the intended repository receives the credentials.

### What is the difference between token-based and SSH authentication in actions/checkout?

Token-based authentication uses HTTPS URLs with an injected `Authorization` header, suitable for most GitHub-hosted runners and requiring no additional key management. SSH authentication requires providing an `ssh-key` input, which the action writes to a temporary file and references via the `GIT_SSH_COMMAND` environment variable. SSH is necessary for accessing repositories in other providers or when specific key-based access controls are required, while tokens are preferred for GitHub-to-GitHub communication due to their automatic rotation and scoped permissions.

### How does the fetch-depth parameter optimize repository fetching?

The `fetch-depth` parameter controls shallow cloning via the `--depth` Git flag. When set to `1` (the default), the action performs a shallow fetch containing only the latest commit, significantly reducing clone time and disk usage for large repositories. Setting `fetch-depth: 0` disables shallow fetching and retrieves full history. The action validates that shallowly-fetched commits match expected SHAs to prevent inconsistencies when refs advance on the remote during the fetch operation.

### Are credentials persisted after the checkout step completes?

By default, credentials are **not** persisted. The action automatically removes temporary SSH keys, known-hosts files, and HTTP authorization configs after the job finishes. However, if `persist-credentials: true` is set—typically required when checking out submodules that reference private repositories—the action retains the credentials config and SSH settings so subsequent steps (like `git submodule update`) can authenticate. These persisted credentials are still scoped to the temporary config files and cleaned up when the job container is destroyed.