specs/055-git-checkout.md
Rama main · réplica de lectura del repositorio original.
# Spec: Git Checkout Action
## Status
Partially implemented.
Conformance uses one small local repository to check fresh clone, unchanged
recheckout, tag checkout, and configuration validation. Executor tests own
ref-resolution permutations, shallow history, upstream updates, dirty
worktrees, and transport behavior.
This spec defines conformance behavior for the built-in `git.checkout`
action.
## Scope
This spec defines `git.checkout`, which clones a repository into a local
path if it does not yet exist there, or fetches and checks it out in
place if it does -- unlike [Spec 030: Git Worktree
Action](030-git-worktree-action.md), which manages linked worktrees
inside an existing repository.
This spec covers:
- the required `with.repository` and `with.path`
- `with.ref`: a branch, tag, or commit to check out; when unset,
the repository's default HEAD is used
- clone-if-absent, fetch-and-checkout-if-present behavior at
`with.path`, and the checkout result's `cloned` and `changed` fields
- `with.depth`: shallow clone/fetch depth
- `with.force`: whether local modifications at an existing target block
a checkout
- authentication fields (`with.token`, `with.username`, `with.password`,
`with.ssh_key_path`, `with.ssh_passphrase`) and the field combinations
that are rejected
- that every configuration error this spec documents is rejected at
DAG-build-time validation, not only at runtime
- validation and runtime errors
This spec does not define:
- live SSH or HTTPS token/password authentication against a real git
server -- this spec exercises unauthenticated local-path repositories
only
- linked worktree management (`git.worktree.add`, `git.worktree.remove`)
-- see [Spec 030: Git Worktree Action](030-git-worktree-action.md)
- replacing an existing checkout's origin with a different repository
- submodules, LFS, or sparse checkout
## Goal
Workflow authors bring a git repository to a known ref on the local
filesystem as a DAG step, whether that means an initial clone or
bringing an existing checkout up to date, without shelling out to `git`
directly.
## Behavior
### Clone or fetch
If `with.path` does not yet contain a repository, `git.checkout` clones
`with.repository` there (creating missing parent directories) and
checks out `with.ref`, or the default HEAD if `with.ref` is unset. If
`with.path` already contains a checkout of the same repository, it fetches
from that checkout's `origin`, then checks out the same way. The
result reports `cloned` (true only on a fresh clone) and `changed` (true
when the checked-out commit differs from what was checked out before, or
on a fresh clone), along with the resolved `commit` hash.
`with.repository` accepts a local filesystem path as well as a remote
URL.
### Ref resolution
`with.ref` may be a branch name, a tag name, or a full commit hash. A full
hash selects that commit directly. A branch name selects the branch as
fetched from `origin`, so a later `git.checkout` against an existing target
picks up new commits on that branch. Ambiguous branch/tag names are outside
this conformance scope. Omitting `with.ref` checks out the
repository's default HEAD, re-resolved on every run -- so a later
`git.checkout` with no `with.ref` against an existing target picks up
new commits added upstream since the last run.
### Local modifications
Without `with.force`, checking out over a target whose worktree has
uncommitted local modifications fails rather than discarding them. With
`with.force: true`, local modifications are discarded and the checkout
proceeds.
### Shallow clone
`with.depth`, when greater than zero, limits how much history a fresh
clone (or a fetch against an existing shallow clone) retrieves.
### Authentication
Exactly one authentication method may be configured: `with.ssh_key_path`
(optionally with `with.ssh_passphrase`) for SSH, or `with.token`, or
`with.username`/`with.password` for HTTPS. `with.ssh_key_path` cannot be
combined with `with.token` or `with.password`; `with.token` cannot be
combined with `with.username` or `with.password`.
SSH key authentication uses `with.username` as the SSH user when it is set,
then the user in `with.repository`, such as `deploy` in
`ssh://deploy@git.example.com/repo.git`, then `git`.
## Errors
### Validation
Every one of these is rejected at DAG-build-time validation (`dagu
validate`), not only when the step runs:
- `with.repository` missing: an error containing `"repository is
required"`.
- `with.path` missing: an error containing `"path is required"`.
- `with.depth` negative: a schema `minimum` error.
- `with.ssh_key_path` combined with `with.token` or `with.password`: an
error containing `"ssh_key_path cannot be combined with token or
password"`.
- `with.token` combined with `with.username` or `with.password`: an
error containing `"token cannot be combined with username/password"`.
- Any `with:` field git.checkout does not support (for example,
`with.branch`, which belongs to `git.worktree.add`): an error
containing `"invalid keys"`.
### Runtime
- `with.path` exists and is not a directory: an error containing `"not
a directory"`.
- `with.path` exists, is a directory, is not a git repository, and is
not empty: an error containing `"target directory is not a git
repository and is not empty"`.
- `with.ref` does not resolve to a branch, tag, or commit in the
repository: an error containing `"not found"`.
- `with.repository` cannot be cloned (does not exist, or is
unreachable): an error containing `"clone failed"`.
- An existing target's worktree has local modifications and
`with.force` is not set: an error containing `"unstaged changes"`.
## Related Specs
- Git worktree management: [Spec 030: Git Worktree
Action](030-git-worktree-action.md)
## Examples
Clone a repository at a specific tag:
```yaml
steps:
- action: git.checkout
with:
repository: https://github.com/example/example.git
path: ./build/src
ref: v1.4.0
depth: 1
```
Bring an existing checkout up to date with its default branch,
discarding any local changes:
```yaml
steps:
- action: git.checkout
with:
repository: https://github.com/example/example.git
path: ./build/src
force: true
```