Skip to content

Repository

Repository manages a single GitHub repository — its description, visibility, topics, labels, features, merge strategy, branch protection rules, rulesets, secrets, variables, and Actions settings.

metadata:
owner: babarot # GitHub owner or organization
name: my-project # Repository name

The combination of owner and name identifies the target repository (babarot/my-project).

FieldDescription
descriptionRepository description
homepageURL displayed on the repo page
visibilitypublic, private, or internal — see General Settings
archivedArchive (read-only) or unarchive — see General Settings
topicsGitHub topics for discoverability
labelsRepository issue/PR labels — see Labels
label_syncDeprecated label sync mode: use reconcile.labels instead — see Labels
featuresToggle issues, projects, wiki, discussions, pull requests — see General Settings
merge_strategyMerge commit, squash, rebase options — see General Settings
branch_protectionClassic branch protection rules — see Branch Protection
rulesetsModern rulesets with enforcement modes and bypass actors — see Rulesets
secretsGitHub Actions secrets (via ${ENV_*} references) — see Secrets & Variables
variablesRepository variables — see Secrets & Variables
actionsGitHub Actions permissions, SHA pinning, workflow defaults, and fork PR policy — see Actions

All fields are optional — declare only what you want to manage. Fields not present in the YAML are left unchanged on GitHub. The one exception is spec.actions.enabled: when managing any other Actions setting, GitHub requires enabled to be sent too. See Actions.

By default, collection fields are managed additively: gh-infra creates or updates entries declared in YAML and leaves undeclared GitHub resources untouched.

Use top-level reconcile to make selected collections match YAML exactly:

reconcile:
rulesets: authoritative
labels: additive
branch_protection: additive
spec:
rulesets:
- name: protect-main
target: branch
rules:
non_fast_forward: true
FieldModesDescription
reconcile.labelsadditive, authoritativeControls how spec.labels is compared with existing GitHub labels
reconcile.rulesetsadditive, authoritativeControls how spec.rulesets is compared with existing GitHub rulesets
reconcile.branch_protectionadditive, authoritativeControls how spec.branch_protection is compared with existing classic branch protection rules

additive is the default. authoritative deletes remote entries that are not declared in YAML, but only when the corresponding spec collection is present. If spec.rulesets, spec.branch_protection, or spec.labels is omitted, that collection is unmanaged even when reconcile has a policy for it.

To delete all labels, rulesets, or branch protection rules, use authoritative with an empty list:

reconcile:
rulesets: authoritative
spec:
rulesets: []

labels: null, labels:, rulesets: null, rulesets:, branch_protection: null, and branch_protection: are invalid. Use an empty list when you mean an empty managed collection.

Use Repository when you want to manage one repo’s settings in a dedicated YAML file. This is the simplest resource kind and the starting point for most users.

It works best when:

  • Each repo has its own distinct settings — different branch protection rules, different topics, different merge strategies.
  • You want per-repo change tracking — each file maps to one repo, so git blame tells you exactly who changed what and when.
  • You’re managing a small number of repos — for 1–5 repos, separate files are easy to maintain.

If you find yourself copying the same settings across many files, consider RepositorySet instead.

If a YAML manifest references a repository that doesn’t exist, plan shows it as a new resource:

$ gh infra plan ./repos/
Plan: 1 to create, 0 to update, 0 to destroy
+ babarot/new-project (new)
+ repository: babarot/new-project

apply creates it with gh repo create, then applies all settings (features, topics, branch protection, etc.) in a single pass.

gh-infra does not support repository deletion. Without a state file, there is no way to distinguish “removed from YAML” from “never managed” — and repository deletion is irreversible.

To delete a repository, use gh repo delete directly.