git snapshots.md
Fast repository checkouts with Git snapshots
Git snapshots prepare a repository and working tree once, package them as a snapshot, and reuse that snapshot across ephemeral runners. A runner downloads and extracts the snapshot instead of fetching Git history and checking out every file itself.
This is most useful for large repositories where checkout time is a significant part of each job. Snapshots are keyed by the resolved commit, so repeated checkouts of the same commit reuse the same immutable snapshot.
NOTE
Git snapshots are in early access. Reach out to enable them for your workspace.
Git snapshots are intended to supersede Git checkout caching.
Requirements
- A GitHub repository.
- A Namespace Linux, macOS, or Windows runner.
- A GitHub association that gives Namespace read-only access to the target organization and repositories.
Use Git snapshots in a workflow
Replace actions/checkout with namespace-actions/code-checkout:
jobs:
test:
runs-on: nscloud-ubuntu-26.04-amd64-8x16
steps:
- uses: namespace-actions/code-checkout@main
- run: go test ./...
By default, the action checks out the workflow's commit ($GITHUB_SHA) into $GITHUB_WORKSPACE. It uses the runner's Namespace credentials, so no GitHub token is needed.
The same step works on Linux and macOS runners, on both x64 and arm64. To run the job on macOS, replace runs-on with your Namespace macOS runner profile.
TIP
Versioned releases of the action are not published yet. Pin it to a full commit SHA for reproducible workflows.
Inputs
| Input | Default | Description |
|---|---|---|
repository |
${{ github.repository }} |
GitHub repository in owner/name form. |
ref |
The workflow SHA for the workflow repository; otherwise the target repository's default branch | Commit, branch, or tag to check out. Use a commit SHA for reproducibility. |
path |
. |
Destination relative to $GITHUB_WORKSPACE. Must be absent or empty and stay inside the workspace. |
additional-refs |
None | Additional refs to include in the local Git data, one per line. Does not change the checked-out ref. |
For example, to check out into a subdirectory and also fetch main for comparison:
- uses: namespace-actions/code-checkout@main
with:
path: source
additional-refs: |
main
For pull requests, the default ref is the workflow SHA, which is normally GitHub's merge commit. To check out the pull request's head commit instead, set ref: ${{ github.event.pull_request.head.sha }}.
Differences from actions/checkout
The action does not support every actions/checkout option:
- It does not clean a nonempty destination or persist GitHub credentials.
- It does not expose submodule, LFS, sparse-checkout, or fetch-depth settings.
- GitHub Enterprise is not supported.
- Snapshot and authentication failures fail the step. There is no fallback to a direct Git clone.
See the action repository for more details.
How it works
Whenever a ref is requested, Namespace generates a snapshot of the repository contents and serves it from an internal Namespace cache. When multiple jobs request the same ref, as commonly happens in CI, the same snapshot is served to each job. This amortizes the checkout time across those jobs. Snapshots are ephemeral and are removed automatically after some time.
Check out multiple private repositories
The runner's default checkout credentials are scoped to the repository that triggered the workflow. To check out multiple private repositories, create a Namespace token with read access to each repository and pass its bearer token as NSGIT_CHECKOUT_TOKEN.
The GitHub association must allow Namespace to read every target repository. A checkout token does not expand the association's access. Create the token in the same Namespace workspace as the runners and GitHub association.
WARNING
Usensgitv0.1.53 or later. Version v0.1.52 and earlier do not supportNSGIT_CHECKOUT_TOKEN.
Permissions with and without Git snapshots
| Checkout mode | NSGIT_CHECKOUT_TOKEN grants |
Separate provisioning credentials |
|---|---|---|
Git snapshots, including namespace-actions/code-checkout |
code/repository:read for each repository and ingress:*:access |
Normal Namespace runner credentials, with code/git/snapshots:*:ensure. |
Direct clone, using nsgit clone --kind direct |
code/repository:read for each repository |
None. |
Direct clones do not use the snapshot service and do not require Git snapshots to be enabled. Git snapshots must be enabled for the runner's workspace.
Create a token for Git snapshots
Install nsc, then sign in with nsc login and select the runner's workspace. Create a token with one code/repository:read grant per repository and an ingress:*:access grant for the snapshot service:
nsc token create \
--name github-multi-repo-checkout \
--expires_in 180d \
--grant '{"resource_type": "code/repository", "resource_id": "https://github.com/acme/application.git", "actions": ["read"]}' \
--grant '{"resource_type": "code/repository", "resource_id": "https://github.com/acme/shared.git", "actions": ["read"]}' \
--grant '{"resource_type":"ingress","resource_id":"*","actions":["access"]}'
Use the canonical HTTPS repository URL, including .git, as the resource ID. To allow all repositories, replace the repository grants with:
{"resource_type":"code/repository","resource_id":"*","actions":["read"]}
Store the returned bearer token as a GitHub Actions secret named NSGIT_CHECKOUT_TOKEN. Do not commit it to the workflow or print it in job logs. Keep the token ID for revocation, and replace the secret before the token expires.
Use the checkout action with Git snapshots
Use one action step per repository and distinct destination paths:
jobs:
test:
runs-on: nscloud-ubuntu-26.04-amd64-8x16
steps:
- uses: namespace-actions/code-checkout@main
env:
NSGIT_CHECKOUT_TOKEN: ${{ secrets.NSGIT_CHECKOUT_TOKEN }}
with:
repository: acme/application
ref: main
path: application
- uses: namespace-actions/code-checkout@main
env:
NSGIT_CHECKOUT_TOKEN: ${{ secrets.NSGIT_CHECKOUT_TOKEN }}
with:
repository: acme/shared
ref: main
path: shared
Use nsgit with Git snapshots
Install or update nsgit on Linux or macOS:
curl -fsSL https://get.namespace.so/nsgit/install.sh | bash
export PATH="$HOME/.local/bin:$PATH"
On a Namespace runner, supply the secret through the step's environment:
- name: Check out both repositories
env:
NSGIT_CHECKOUT_TOKEN: ${{ secrets.NSGIT_CHECKOUT_TOKEN }}
run: |
nsgit clone github.com/acme/application@main application
nsgit clone github.com/acme/shared@main shared
Use nsgit without Git snapshots
Install nsgit as described above. Create a separate token with only repository read grants, without the ingress grant:
nsc token create \
--name github-direct-checkout \
--expires_in 30d \
--grant '{"resource_type": "code/repository", "resource_id": "https://github.com/acme/application.git", "actions": ["read"]}' \
--grant '{"resource_type": "code/repository", "resource_id": "https://github.com/acme/shared.git", "actions": ["read"]}'
Store its bearer token as a GitHub Actions secret named NSGIT_DIRECT_CHECKOUT_TOKEN and select --kind direct explicitly:
- name: Check out both repositories without snapshots
env:
NSGIT_CHECKOUT_TOKEN: ${{ secrets.NSGIT_DIRECT_CHECKOUT_TOKEN }}
run: |
nsgit clone --kind direct github.com/acme/application@main application
nsgit clone --kind direct github.com/acme/shared@main shared