plan
Show diff between YAML and current GitHub state. No mutations are made.
gh infra plan [path...]One or more paths can be given. When multiple paths are provided, manifests from all paths are collected and planned together.
| Argument | Example | Behavior |
|---|---|---|
(none) or . |
gh infra plan |
All *.yaml / *.yml in the current directory |
| File | gh infra plan repos/my-cli.yaml |
That file only |
| Directory | gh infra plan repos/ |
All *.yaml / *.yml directly under it (subdirectories are ignored) |
| Multiple | gh infra plan repos/ files/ |
Manifests from all listed paths combined |
Overlapping paths (e.g., . and ./repos/) are rejected to prevent duplicate processing.
YAML files that are not gh-infra manifests are silently skipped. Use --fail-on-unknown to treat them as errors.
| Flag | Description |
|---|---|
-r, --repo <owner/repo> |
Target a specific repository |
--detailed-exitcode |
Exit with 2 if changes are detected, 1 on error, 0 otherwise (see Exit status) |
--ci |
Deprecated: use --detailed-exitcode. Exits with 1 if changes are detected, and disables colors |
--changed-since <ref> |
Only the manifests changed since a git ref, and those that read a changed local file. See Only what changed |
--fail-on-unknown |
Error on YAML files with unknown Kind (default: silently skip) |
--concurrency <n> |
Maximum number of gh processes (GitHub API calls) at once, across the whole command. Default 8, or GH_INFRA_CONCURRENCY. Lower it if you hit GitHub’s secondary rate limit or network timeouts |
--diff |
Show a unified diff for each FileSet file change, capped at 500 lines per file. Deleted files show no diff |
-o, --output <format> |
text (default), json, or markdown. See JSON output and Markdown output |
Exit status
Section titled “Exit status”| Code | Meaning |
|---|---|
0 |
Plan computed for every repository (with --detailed-exitcode: and no changes) |
1 |
An error, or the current state of one or more repositories could not be fetched. With --detailed-exitcode, also an interrupted plan and paths with no manifests |
2 |
Changes detected (--detailed-exitcode only) |
An error wins over changes: a plan with changes that also skipped a repository exits with 1. Without --detailed-exitcode, changes alone exit with 0.
--ci is deprecated and will be removed in a future release. It exits with 1 for changes as well as errors, so a job cannot tell them apart; switch to --detailed-exitcode. --ci also disabled colors; set NO_COLOR=1 for that.
plan reads only the settings each manifest sets, so the token needs only their permissions (see Authentication). When fetching fails for a repository (for example, the token cannot read a setting the manifest manages), its error is shown and the repository is left out of the plan; an unreadable setting is never compared as if it were absent or at its default. A plan with skipped repositories is incomplete, so plan exits with 1 even if the other repositories have no changes. A file that cannot be fetched is never treated as missing, so no create is planned for it. A repository that is already archived is reported and left out the same way when the manifest changes it without archived: false, since gh-infra does not change an archived repository except to unarchive it.
Examples
Section titled “Examples”# Plan all YAML files in a directorygh infra plan ./repos/
# Plan multiple directories at oncegh infra plan ./repos/ ./files/
# Plan a single filegh infra plan ./repos/my-cli.yaml
# Plan a specific repositorygh infra plan ./repos/ --repo babarot/my-cli
# CI drift detection (exit 2 when changes are detected)gh infra plan ./repos/ --detailed-exitcode
# Plan only what changed on this branchgh infra plan ./repos/ --changed-since origin/main
# Show the content changes of FileSet filesgh infra plan ./files/ --diff