# How the persist-credentials Input Affects Git Authentication in actions/checkout

> Understand how the persist-credentials input in actions/checkout impacts Git authentication. Learn how it enables subsequent steps to access private repositories by reusing established credentials.

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

---

**The `persist-credentials` input determines whether the GitHub Actions runner retains the authentication token or SSH key in the local Git configuration after the checkout step finishes, defaulting to `true` to allow subsequent steps to reuse credentials for private repository access.**

The `actions/checkout` repository provides this boolean input to balance convenience against security hygiene in CI/CD workflows. When enabled, the action writes the provided `token` or SSH key into Git config files and temporary credential stores that persist for the remainder of the job. When disabled, the action immediately purges these configurations after the initial clone or fetch completes, limiting the window of exposure for sensitive authentication material.

## How persist-credentials Works

The input is defined in [`action.yml`](https://github.com/actions/checkout/blob/main/action.yml) with a default value of `true`. Internally, the flag is read in [`src/input-helper.ts`](https://github.com/actions/checkout/blob/main/src/input-helper.ts) (lines 167-169) and stored in the `IGitSourceSettings` interface defined in [`src/git-source-settings.ts`](https://github.com/actions/checkout/blob/main/src/git-source-settings.ts). The actual behavioral split occurs in [`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts) and [`src/git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts), where the action either preserves or removes Git authentication configurations based on this setting.

### Default Behavior (persist-credentials: true)

When `persist-credentials` is set to `true` (the default), the checkout action performs the following:

- Writes the authentication token or SSH key into the local Git configuration ([`src/git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts), lines 161-168)
- Creates a temporary credentials configuration file and adds `includeIf.gitdir:` entries so that Git commands executed inside Docker containers can access the same authentication ([`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts), lines 291-296)
- Leaves these configurations intact after the checkout step completes, allowing subsequent workflow steps to interact with private repositories or fetch additional refs without re-authenticating

This persistence is particularly important for workflows that fetch private submodules. The action specifically handles submodule authentication by preserving credentials when `settings.persistCredentials` evaluates to true in [`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts).

### Non-Persistent Mode (persist-credentials: false)

Setting `persist-credentials: false` triggers a cleanup routine immediately after the checkout completes:

- The action removes all authentication configurations from the Git config, including the `core.sshCommand` settings and token-based helpers ([`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts), lines 319-321)
- The temporary credentials file is deleted and `includeIf` entries are stripped, ensuring no residual secrets remain on the runner
- Subsequent Git commands that require authentication (such as fetching private branches or submodules) will fail unless explicitly provided with fresh credentials

In [`src/git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts), the logic that configures `core.sshCommand` and writes temporary credential files is skipped entirely when the persist flag is disabled.

## Security Implications and Submodule Behavior

The choice between persistent and non-persistent credentials carries significant security and functionality tradeoffs.

**Security Boundary:** When `persist-credentials` is enabled, the authentication token remains in the global Git configuration and environment variables for all subsequent steps in the job. Any compromised action or malicious script running later in the workflow could exfiltrate this token. Setting the input to `false` constrains the credential lifetime strictly to the checkout action itself.

**Private Submodules:** Workflows cloning private submodules generally require `persist-credentials: true`. The action uses the preserved token to configure submodule authentication via `includeIf.gitdir:` directives. Without persistence, submodule fetch operations fail because the temporary credentials are removed before the submodule initialization step executes.

**Container Jobs:** For jobs running inside Docker containers, the action writes a container-side include path (typically under `/github/runner_temp/`) only when persistence is enabled. This ensures Git processes inside the container can access the token, but it also extends the credential exposure into the container environment.

## Configuration Examples

### Basic Usage with Default Persistence

The default configuration leaves credentials active for later steps:

```yaml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout with default persistence
        uses: actions/checkout@v4
        with:
          token: ${{ secrets.PAT }}
          # persist-credentials defaults to true

      - name: Use token in a later step
        run: |
          git fetch origin private-branch

```

The `git fetch` succeeds because the Personal Access Token remains in the repository's Git config.

### Disabling Credential Persistence

To remove authentication immediately after checkout:

```yaml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout without persisting credentials
        uses: actions/checkout@v4
        with:
          token: ${{ secrets.PAT }}
          persist-credentials: false

      - name: Attempt private fetch
        run: |
          git fetch origin private-branch || echo "fetch failed as expected"

```

The subsequent fetch fails because [`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts) has already executed its cleanup block (lines 319-321), removing the token from the configuration.

### Private Submodules with Persistence

When fetching private submodules, persistence is required:

```yaml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repo with private submodule
        uses: actions/checkout@v4
        with:
          submodules: recursive
          persist-credentials: true

      - name: Verify submodule fetched
        run: |
          git -C path/to/submodule status

```

Without `persist-credentials: true`, the submodule fetch would fail because the temporary credentials configured in [`src/git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts) would be unavailable during the recursive clone operation.

## Source Code Architecture

The implementation spans several TypeScript files in the repository:

- **[`src/input-helper.ts`](https://github.com/actions/checkout/blob/main/src/input-helper.ts)** (lines 167-169): Reads the `persist-credentials` input from the workflow and assigns it to `result.persistCredentials`
- **[`src/git-source-settings.ts`](https://github.com/actions/checkout/blob/main/src/git-source-settings.ts)**: Defines the `persistCredentials` boolean in the `IGitSourceSettings` interface
- **[`src/git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts)** (lines 161-168): Conditionally configures token and SSH authentication based on the `persistCredentials` setting
- **[`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts)** (lines 291-296, 319-321): Handles the persistence logic for submodules and executes the cleanup routine when persistence is disabled
- **[`action.yml`](https://github.com/actions/checkout/blob/main/action.yml)**: Declares the input with its default value and documentation

## Summary

- The `persist-credentials` input in `actions/checkout` defaults to `true`, leaving authentication tokens in the Git config after checkout
- When set to `false`, the action removes all credential configurations immediately after the initial clone, as implemented in [`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts)
- Private submodules require `persist-credentials: true` to fetch successfully because the action relies on persistent `includeIf` configurations
- Security-conscious workflows should disable persistence to prevent credential exposure to subsequent steps, though this requires manual authentication for later Git operations
- The implementation spans [`src/input-helper.ts`](https://github.com/actions/checkout/blob/main/src/input-helper.ts), [`src/git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts), and [`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts), with conditional logic based on the `IGitSourceSettings.persistCredentials` boolean

## Frequently Asked Questions

### What happens to the Git token when persist-credentials is set to false?

When `persist-credentials` is set to `false`, the actions/checkout repository removes the authentication token from the Git configuration immediately after the initial checkout completes. According to the source code in [`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts) (lines 319-321), the cleanup block executes before the action finishes, deleting temporary credential files and removing `core.sshCommand` configurations that the token relies upon.

### Can I fetch private submodules if persist-credentials is false?

No, fetching private submodules will fail if `persist-credentials` is set to `false`. The action configures submodule authentication using temporary credential files and `includeIf.gitdir:` directives in [`src/git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts) (lines 161-168) only when persistence is enabled. Without these preserved configurations, the subsequent submodule fetch operations lack authentication credentials.

### Does persist-credentials affect SSH key authentication as well as tokens?

Yes, the `persist-credentials` input controls both HTTPS token-based authentication and SSH key authentication. In [`src/git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts), the logic that sets `core.sshCommand` to use a specific SSH key respects the `settings.persistCredentials` flag. When disabled, the action skips configuring the SSH command, and any SSH-based Git operations in subsequent steps will fail unless the runner has independent SSH agent access.

### Is it safe to leave persist-credentials set to true?

Leaving `persist-credentials` set to `true` is convenient but increases the attack surface. The token remains in the Git configuration and environment for all subsequent workflow steps, meaning any compromised action or injection vulnerability could potentially access the credential. For high-security environments or workflows that do not need subsequent Git operations, GitHub recommends setting `persist-credentials: false` to minimize the credential exposure window.