# How fetch-tags Works in actions/checkout: Source Code Deep Dive

> Understand how fetch-tags in actions/checkout works. Learn how this input conditionally adds Git tag references for efficient fetching. Dive into the source code.

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

---

**The `fetch-tags` input in `actions/checkout` controls whether Git tags are fetched during repository checkout by conditionally adding the ref-spec `+refs/tags/*:refs/tags/*` to the fetch operation based on the Boolean value parsed in [`src/input-helper.ts`](https://github.com/actions/checkout/blob/main/src/input-helper.ts).**

The `actions/checkout` action is the standard method for cloning repositories in GitHub Actions workflows. While the `fetch-tags` input appears simple, its implementation involves sophisticated ref-spec manipulation in the TypeScript source. This article examines how the action processes this input, from YAML parsing in [`src/input-helper.ts`](https://github.com/actions/checkout/blob/main/src/input-helper.ts) to the Git command generation in [`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts).

## Parsing the fetch-tags Input in src/input-helper.ts

The lifecycle begins in [`src/input-helper.ts`](https://github.com/actions/checkout/blob/main/src/input-helper.ts), where the `getInputs()` function processes workflow configuration. The action reads the `fetch-tags` input as a string and converts it to a Boolean by comparing the uppercase value to `'TRUE'`.

```ts
// src/input-helper.ts
result.fetchTags =
  (core.getInput('fetch-tags') || 'false').toUpperCase() === 'TRUE';

```

This conversion means any value other than `true` or `TRUE` defaults to `false`, including empty strings or omitted inputs.

## Ref-Spec Construction Logic in src/ref-helper.ts

The core logic resides in [`src/ref-helper.ts`](https://github.com/actions/checkout/blob/main/src/ref-helper.ts), which defines the `tagsRefSpec` constant and the `getRefSpec()` function. This function determines whether to include tag references based on the `fetchTags` parameter and the nature of the requested ref.

```ts
// src/ref-helper.ts
const tagsRefSpec = '+refs/tags/*:refs/tags/*';
function getRefSpec(ref, commit, fetchTags) {
    // …
    if (fetchTags) {
        result.push(tagsRefSpec);          // always fetch tags
    }
    // …
    else if (!upperRef.startsWith('REFS/')) {
        // unqualified ref – fetch tags only if fetchTags is false
        if (!fetchTags) {
            result.push(`+refs/tags/${ref}*:refs/tags/${ref}*`);
        }
    }
}

```

When `fetch-tags` is set to `true`, the action always appends `+refs/tags/*:refs/tags/*` to the fetch ref-specs. When `false` (the default), tags are only fetched for unqualified refs—plain tag names that do not start with `refs/`.

## Fetch Execution and Tag Verification in src/git-source-provider.ts

In [`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts), the orchestration layer calls `getRefSpec()` with the settings from the input helper, then executes the fetch:

```ts
// src/git-source-provider.ts
const refSpec = getRefSpec(settings.ref, settings.commit, settings.fetchTags);
await git.fetch(refSpec, fetchOptions);

```

After fetching, the action validates tag integrity using `testRef()` to ensure fetched tags point to the commits that triggered the workflow. This prevents race conditions where a tag moves between the trigger event and the checkout operation.

## Practical Workflow Examples

Here are common patterns for using `fetch-tags` in `.github/workflows/`:

```yaml

# .github/workflows/checkout-tags.yml

name: Checkout with tags

on: [push]

jobs:
  demo:
    runs-on: ubuntu-latest
    steps:
      # 1️⃣ Default – tags are NOT fetched

      - uses: actions/checkout@v4

      # 2️⃣ Explicitly fetch all tags (useful for release workflows)

      - uses: actions/checkout@v4
        with:
          fetch-tags: true   # <-- forces +refs/tags/*:refs/tags/*

      # 3️⃣ Fetch only a single tag (unqualified ref)

      - uses: actions/checkout@v4
        with:
          ref: v1.2.3        # unqualified tag name; tags fetched automatically

```

In the first step, only the branch commit is fetched. The second step pulls every tag in the repository. The third step automatically adds tag-specific ref-specs because `v1.2.3` is an unqualified ref, even without setting `fetch-tags: true`.

## Summary

- **Input parsing**: [`src/input-helper.ts`](https://github.com/actions/checkout/blob/main/src/input-helper.ts) converts `fetch-tags` from string to Boolean using case-insensitive comparison to `'TRUE'`.
- **Ref-spec logic**: [`src/ref-helper.ts`](https://github.com/actions/checkout/blob/main/src/ref-helper.ts) conditionally includes `+refs/tags/*:refs/tags/*` when `fetchTags` is true, or adds specific tag patterns for unqualified refs when false.
- **Default behavior**: Tags are not fetched unless the ref is an unqualified tag name or `fetch-tags: true` is explicitly set.
- **Security**: [`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts) validates fetched tags against the original commit using `testRef()` to prevent moving tag attacks.
- **Performance**: Omitting `fetch-tags` reduces network traffic and speeds up shallow clones by excluding tag references.

## Frequently Asked Questions

### What is the default value of fetch-tags in actions/checkout?

By default, `fetch-tags` is `false` when omitted from the workflow configuration. The input parser in [`src/input-helper.ts`](https://github.com/actions/checkout/blob/main/src/input-helper.ts) defaults the value to `'false'` before converting it to a Boolean, meaning tags are not fetched unless explicitly requested or the ref is an unqualified tag name.

### Does fetch-tags: true fetch all tags or only specific ones?

Setting `fetch-tags: true` fetches all tags in the repository. According to [`src/ref-helper.ts`](https://github.com/actions/checkout/blob/main/src/ref-helper.ts), this setting causes the action to include `+refs/tags/*:refs/tags/*` in the fetch ref-specs, which pulls every tag reference. To fetch only a specific tag without pulling all tags, use the `ref` input with an unqualified tag name like `v1.0.0` instead of setting `fetch-tags`.

### When should I use fetch-tags: true versus leaving it as the default?

Use `fetch-tags: true` when your workflow needs access to the complete tag history, such as release automation, changelog generation, or version comparison scripts. Leave it as the default (`false`) for standard CI builds where only the specific commit matters, as this reduces fetch time and network bandwidth by skipping tag objects.

### How does actions/checkout verify fetched tags after checkout?

After executing `git.fetch()`, the action calls `testRef()` in [`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts) to validate that any fetched tag still points to the expected commit SHA. This verification prevents the checkout from succeeding if a tag was moved between the workflow trigger and the fetch operation, ensuring reproducible builds.