# How the safe.directory Configuration Works in actions/checkout

> Learn how actions/checkout configures the safe directory setting to prevent fatal unsafe repository errors when running in Docker or with different user UIDs.

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

---

**The `actions/checkout` action automatically configures Git's `safe.directory` setting to prevent "fatal: unsafe repository" errors when running in Docker containers or under different user UIDs.**

The `actions/checkout` action configures Git's **safe.directory** setting to prevent ownership-related failures in containerized workflows. When Git 2.35+ detects a repository directory owned by a different user, it aborts operations with a fatal error. The action automatically handles this security feature by adding the repository path to Git's safe directory list, ensuring reliable checkouts across diverse execution environments.

## Understanding Git's safe.directory Requirement

Git 2.35 introduced stricter ownership checks that treat repositories owned by different users as potentially unsafe. When running jobs inside Docker containers, the mounted workspace often has a UID that differs from the container's default user, triggering the "fatal: unsafe repository" error. The **safe.directory** configuration tells Git to trust specific paths regardless of ownership, allowing operations to proceed securely.

## How actions/checkout Implements safe.directory

The implementation spans three core components that parse inputs, configure Git, and persist state across the job lifecycle.

### Input Parsing in input-helper.ts

In [`src/input-helper.ts`](https://github.com/actions/checkout/blob/main/src/input-helper.ts) (lines 74-77), the action reads the boolean input `set-safe-directory`, which defaults to `true`. This value is stored in `result.setSafeDirectory` and passed to the git source provider.

### Temporary Global Configuration in git-source-provider.ts

When `setSafeDirectory` is enabled, [`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts) (lines 45-63) executes `git config --global` to add the repository path to the safe directory list. This creates a temporary global Git configuration that applies to the current job. The helper also calls `stateHelper.setSafeDirectory()` to record that the configuration was applied.

### State Persistence in state-helper.ts

The [`src/state-helper.ts`](https://github.com/actions/checkout/blob/main/src/state-helper.ts) module (lines 14-22) uses `core.saveState()` to persist the `set-safe-directory` flag in the GitHub Actions state bag. This allows the POST-action cleanup phase to detect whether the safe directory configuration was applied, ensuring proper cleanup and idempotency.

## Configuring safe.directory in Your Workflows

You can control this behavior through the `set-safe-directory` input or handle it manually.

### Default Behavior

```yaml
steps:
  - uses: actions/checkout@v4

```

With `set-safe-directory` defaulting to `true`, the action automatically adds `$GITHUB_WORKSPACE` to Git's safe directories.

### Disabling Automatic Configuration

```yaml
steps:
  - uses: actions/checkout@v4
    with:
      set-safe-directory: false

```

Setting this to `false` skips the automatic configuration. Only use this when the job runs with the same UID as the runner or when you manage the configuration separately.

### Manual Configuration

```yaml
steps:
  - name: Add safe directory manually
    run: |
      git config --global --add safe.directory $GITHUB_WORKSPACE
  - uses: actions/checkout@v4
    with:
      set-safe-directory: false

```

This approach gives you full control over Git's configuration while preventing duplicate entries.

## Summary

- **`actions/checkout`** automatically configures `safe.directory` to prevent Git ownership errors in containerized environments.
- The **`set-safe-directory`** input (default `true`) controls whether the action modifies Git's global configuration.
- Implementation spans **[`src/input-helper.ts`](https://github.com/actions/checkout/blob/main/src/input-helper.ts)**, **[`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts)**, and **[`src/state-helper.ts`](https://github.com/actions/checkout/blob/main/src/state-helper.ts)** to handle parsing, configuration, and state persistence.
- Git 2.35+ requires this configuration when the repository owner differs from the current user, which is common in Docker workflows.

## Frequently Asked Questions

### What is the safe.directory configuration in Git?

The `safe.directory` configuration is a Git security feature introduced in version 2.35 that specifies directories Git should consider safe regardless of ownership. By default, Git refuses to operate on repositories owned by users other than the current process owner to prevent security risks from malicious `.git` directories.

### Why does actions/checkout need to configure safe.directory?

Containerized workflows often mount the workspace directory with a UID different from the container's default user. Without adding the path to `safe.directory`, Git would abort with "fatal: unsafe repository" errors. The action automatically configures this to ensure checkout operations succeed regardless of the user context.

### Can I disable the safe.directory configuration?

Yes. Set `set-safe-directory: false` in the action inputs. This skips the automatic configuration in [`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts). Only disable this if you are certain the job runs with matching UIDs or if you configure the safe directory manually before the checkout step.

### Where is the safe.directory state stored between action phases?

The action uses `core.saveState()` in [`src/state-helper.ts`](https://github.com/actions/checkout/blob/main/src/state-helper.ts) to store a flag in the GitHub Actions state bag. This persists the configuration status between the main action and POST-action phases, allowing the cleanup process to reference the original settings.