Self-hosted service
actions/checkout avatar
actions/checkout

actions/checkout v7: what the fork pull request block changes

Action for checking out a repo

9,015 stars2,748 forksTypeScriptMIT

At a glance

What is it?
GitHub's checkout action now refuses to check out fork pull request code under pull_request_target or workflow_run unless you set allow-unsafe-pr-checkout. Here is the mechanism, the install path, and where the action stops being the right tool.
Who is it for?
Use actions/checkout when a workflow needs repository contents in $GITHUB_WORKSPACE, especially if you want sparse-checkout, a shallow fetch-depth, or a token that persists for later git commands. Do not use it as a general git client for arbitrary remotes, and do not expect contributions: the README states the project is not taking them.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 28 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • actions/checkout9,015 ★ · +114
Star history
Repository2026-09-222026-11-13
actions/checkout8.9k9k

114 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

What actions/checkout is for, and who actually needs it

Every GitHub Actions job starts on a runner with an empty workspace. The README states the action checks out your repository under $GITHUB_WORKSPACE so the workflow can access it. That single sentence defines the audience: anyone whose job needs source files, a build script, a test suite, or a git history to run against. If your job only calls an external API or publishes an artifact built elsewhere, you do not need it, and adding it costs a fetch.

The default behaviour is deliberately narrow. Only a single commit is fetched by default, for the ref or SHA that triggered the workflow. That is a real design decision with consequences: a job that runs git log, computes a changelog, or depends on tags needs fetch-depth: 0, because the default history is one commit deep. The README points at the GitHub documentation to learn which commit $GITHUB_SHA points to for different events, which is the part people get wrong most often when they assume the default ref matches their branch.

The action also handles the case where Git is not usable. When Git 2.18 or higher is not in your PATH, it falls back to the REST API to download the files. That fallback exists for runners and container images that ship without a recent git, and it means the action is not simply a wrapper around a git binary.

The v7 change: refusing fork pull request code by default

The headline in the v7 release notes is not a performance improvement. Checkout now refuses to check out fork pull request code by default when the workflow is triggered by pull_request_target or workflow_run. The README explains the reasoning directly: those triggers run with the base repository's GITHUB_TOKEN, secrets, and runner access, where executing a fork's code commonly leads to pwn request vulnerabilities. This is a breaking change for any repository that relied on the old behaviour, and it is the right kind of breaking change, because the old behaviour was a security footgun that many workflows inherited by copy and paste.

The opt-in is explicit and named for what it does: set allow-unsafe-pr-checkout: true. The README links to guidance on securely using pull_request_target before you do that. If a workflow of yours suddenly fails after upgrading to v7, this default is the first thing to check, not the ref or the token.

The v7 release also migrated the action to ESM to support new versions of the @actions/* packages and updated direct and transitive dependencies, including security fixes for known vulnerabilities. Those are maintenance items rather than features, but they explain why the major version moved.

Credentials, cleanup, and the v6 storage change

By default the action persists credentials so that later steps can run authenticated git commands such as git fetch and git push. In v6 that storage moved: persist-credentials now stores credentials in a separate file under $RUNNER_TEMP instead of directly in .git/config. The README states no workflow changes are required and that authenticated git commands continue to work. The token is removed during post-job cleanup, and persist-credentials: false opts out entirely.

One constraint from that change is easy to miss. Running authenticated git commands from a Docker container action requires Actions Runner v2.329.0 or later. If you pin an older self-hosted runner, that requirement is not met.

Adding actions/checkout to a workflow and running a first sparse checkout

There is no package to install. The action is consumed from a workflow file, and the README gives the usage block for actions/checkout@v7. A minimal job that only needs the default single commit looks like this.

yaml
- uses: actions/checkout@v7
  with:
    repository: ''
    ref: ''
    token: ''

The reader should see the repository contents appear in $GITHUB_WORKSPACE before later steps run, with one commit of history. Those three inputs are the first entries in the README's usage block, and leaving them empty means the defaults apply: the repository that triggered the workflow and the ref or SHA for that event.

If your job needs history or tags, add the inputs rather than scripting a fetch. fetch-depth: 0 fetches all history for all branches and tags.

yaml
- uses: actions/checkout@v7
  with:
    fetch-depth: 0

For large monorepos the more interesting inputs are sparse-checkout and filter. The README's examples pass sparse-checkout patterns on separate lines, and set sparse-checkout-cone-mode: false to fetch a single file.

yaml
- uses: actions/checkout@v7
  with:
    sparse-checkout: |
      packages/api
      packages/shared

The reader should see only those paths materialised in the workspace.

Where actions/checkout is the wrong tool

The action checks out a repository into the workspace of a job. It is not a general purpose git client. If you need to clone several unrelated repositories into distinct directories, you must either use the path input to place each one under $GITHUB_WORKSPACE or run git clone yourself; the action's repository input names one repository with owner, defaulting to ${{ github.repository }}. For a matrix that pulls a dozen third party repositories, hand written git commands are usually clearer than a wall of checkout steps with path overrides.

The maintainer position is also a limitation. The README states plainly that the project is not taking contributions right now, that questions and support requests go to Community Discussions, that high priority bugs can be reported there or to support, and that security issues follow security.md. The README adds that security updates will still be provided and major breaking changes fixed during this period. So fixes arrive, but outside contributions do not, and a feature you want will not land through a pull request.

Finally, the runtime floor matters. v5 moved to the node24 runtime and requires a minimum Actions Runner version of v2.327.1. v6 raised the bar for container actions to v2.329.0. Self-hosted fleets pinned below v2.327.1 cannot run v5, and below v2.329.0 lose authenticated git in Docker container actions.

The alternative: skipping checkout and driving git directly

The obvious alternative is not another checkout action. It is a run step that calls git yourself. The difference is control versus defaults. A raw git command gives you any remote, any depth, any refspec, and no opinion about credentials, but you then own the token setup, the cleanup, the host key handling, and the fallback when git is absent. actions/checkout packages those decisions: token configuration, cleanup in a post-job step, and a REST API download path when Git 2.18 or higher is not in PATH.

The practical split is this. If your job checks out the repository that triggered the workflow, or one repository named explicitly, use the action and let it manage the credential lifecycle. If your job needs arbitrary clone topologies, submodules fetched in unusual ways, or git behaviour the action does not expose, write the git commands and accept that you are now responsible for removing the token when the job ends. The action's own README frames the credential handling as its value: the token is configured with the local git config so your scripts can run authenticated git commands, and the post-job step removes it.

Maintenance, upgrades, and the MIT licence

The repository is not archived, and the last push was on 2026-10-17. Recent releases include v7.0.1, v3.7.0, and v2.8.0, all published on 2026-07-20, which shows that older major lines received releases alongside the current one.

Upgrade cost is concentrated in two places. Moving to v7 forces you to audit every workflow triggered by pull_request_target or workflow_run, because the default now refuses fork pull request code; the README gives allow-unsafe-pr-checkout: true as the opt-in. Moving to v6 or v5 forces a runner version check, v2.329.0 for authenticated git in Docker container actions and v2.327.1 for the node24 runtime. The package.json declares engines.node as >=24, which is about building the action, not consuming it.

The action is MIT licensed, and the repository carries a .licensed.yml plus a .licenses/ directory, which indicates the project tracks its dependency licences. MIT is permissive, so embedding the action in a commercial workflow raises no licensing question in itself; the dependency licences recorded in .licenses/ are a separate matter, and if your organisation reviews third party licences, that directory is where to look rather than the top level LICENSE file.

Editorial conclusion

Use actions/checkout when a workflow needs repository contents in $GITHUB_WORKSPACE, especially if you want sparse-checkout, a shallow fetch-depth, or a token that persists for later git commands. Do not use it as a general git client for arbitrary remotes, and do not expect contributions: the README states the project is not taking them. Before upgrading to v7, check every workflow triggered by pull_request_target or workflow_run, because the default now refuses fork pull request code and the fix is either allow-unsafe-pr-checkout: true or a redesign of the trigger.

Frequently asked questions

What does actions/checkout do in a GitHub Actions workflow?

It checks out your repository under $GITHUB_WORKSPACE so the workflow can access it. By default it fetches only a single commit, for the ref or SHA that triggered the workflow.

How do I use actions/checkout to fetch the full git history?

Set fetch-depth: 0, which the README describes as fetching all history for all branches and tags.

Why does actions/checkout v7 refuse to check out fork pull request code?

Because pull_request_target and workflow_run run with the base repository's GITHUB_TOKEN, secrets, and runner access, where executing a fork's code commonly leads to pwn request vulnerabilities. You can opt in with allow-unsafe-pr-checkout: true after reviewing the linked risks.

Where are credentials stored when persist-credentials is enabled?

In v6 and later they are stored in a separate file under $RUNNER_TEMP instead of directly in .git/config, and the README states no workflow changes are required. The token is removed during post-job cleanup.

Does actions/checkout work if git is not installed on the runner?

Yes. When Git 2.18 or higher is not in your PATH, the action falls back to the REST API to download the files.

Official sources

  1. actions/checkout on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/actions-checkout.svg)](https://hysenlabs.com/projects/actions-checkout)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/actions-checkout.svg)](https://hysenlabs.com/projects/actions-checkout)

Was this useful?