Skip to content

Latest commit

 

History

History
386 lines (297 loc) · 18.9 KB

configuration.md

File metadata and controls

386 lines (297 loc) · 18.9 KB

3. Configuration file reference

Where the file lives

.gitscale.toml, at the top of the workspace's root repository — anywhere else, GitScale refuses. Every command searches upward from the current directory, past any checkout GitScale made, to the workspace root — see finding the workspace; -C, --root PATH starts the search from PATH instead.

A checked-out sub-repository may carry its own .gitscale.toml. Which parts of it are read, and when, is covered under nested configs.

Unknown keys and unknown tables are ignored on read, except inside [artefact], [resolve], [branches], [topic] and [forward], where a misspelt key would quietly do less than meant. git scale require and unrequire and git upgrade edit the file in place: comments, key order and unknown tables are kept.

A complete example

[repos]
"imports/core"  = { url = "git@github.com:org/core.git", revision = "main" }
"imports/utils" = { url = "https://github.com/org/utils.git", revision = "v2.1.0" }
"meta/frontend" = { url = "https://github.com/org/frontend.git", revision = "main" }
"vendor/tools"  = { url = "https://github.com/org/tools.git", recursive = false }

[registries]
"gitlab.corp.example" = "registry.corp.example"

[artefact]
include = ["dist/**"]
exclude = ["**/*.map"]

[branches]
pinned = ["main", "staging", "release/*"]

[topic]
prefix = "{user}/"

[clean]
exclude     = [".vscode", ".idea", ".env", "envs/", "tmp"]
keep_recent = "3months"

[hooks]
post_sync     = "make install"
on_pull_error = "warn"

[forward]
parallel = 8

Every table is optional. A config with nothing but [clean] in it is valid and useful — see per-repo [clean].

[repos]

A table of entries, keyed by the directory the checkout lands in, relative to the config.

[repos]
"imports/core" = { url = "git@github.com:org/core.git", revision = "main", recursive = true }
Key Type Default Meaning
url string required Repository URL: HTTPS, SSH (git@host:owner/repo.git or ssh://git@host/owner/repo.git), or a local path
revision string "" Branch, tag or full commit SHA (40 or 64 hex digits). A minimum: resolution may raise it to what a dependency asks for. Empty asks for nothing, leaving it to the dependencies — or, when nobody asks, the remote's default branch. See pinning a revision
recursive bool true Read this repository's own .gitscale.toml: resolve its transitive dependencies, and clean it by its own [clean] rules. With false, that config is not read at all, and clean cleans the repository without its keep-list
override bool false Exactly this revision, and nothing higher: wins over every request from a repository below this one, and must agree with the rest. Needs a revision. See overrides
singleton bool unset true: this repository may be checked out only once, whatever majors are asked for. false: relaxes a true from repositories below this one. See singleton
lazy bool false Checked out only once it is named — git scale sync DIR or git topic join DIR — or the topic has a branch of it, and kept from then on while it is on disk. A request from any other repository that is not lazy makes it an ordinary entry. A workspace's git scale prefer --eager overrides it, and --lazy makes an entry of the root's lazy, never one another repository needs. See only when needed

The directory key must be relative and free of .., and must not be empty. Two entries for one repository need revisions to tell which major each is for.

[resolve]

How dependencies the root does not declare are checked out. Read from the root only.

[resolve]
hoist_dir = "imports"
allow = ["github.com/partner-org/*", "gitlab.example.com/platform/*"]
Key Type Default Meaning
hoist_dir string "imports" Where implicit checkouts go, relative to the config. Must stay inside the workspace
allow list of strings [] Patterns for repositories an implicit dependency may come from, on top of the host and owner of every repository the root declares. Globs over host/owner/repo, as hook install --allow takes them; * crosses /, so github.com/org/* covers nested groups. A local path is allowed only by a pattern here

singleton

singleton = true

[repos]
# …

A top-level key, before any table: this repository says of itself that a workspace may hold only one checkout of it. Read from a dependency's config at the revision selected. See singleton.

[registries]

Where artefacts are published, for repositories the built-in mapping does not cover. GitHub, GitLab.com and the registry a CI job's own server owns need nothing here — see where artefacts live.

[registries]
"gitlab.corp.example" = "registry.corp.example"
"/srv/repos/"         = "registry.corp.example:5000/mirrors"
Key Value
a host, such as gitlab.corp.example The registry for every repository on that host, as host[:port][/namespace]. The image is <registry>/<repo path>/gitscale
anything containing /: a URL prefix The registry for every repository URL starting with it, on a path boundary. The longest matching prefix wins, and the image path is what follows the prefix

Both kinds of key and value must be non-empty. A value carries no scheme, except http:// to opt in to plain HTTP for a registry without TLS. A registry on localhost, 127.0.0.1 or [::1] is spoken to over plain HTTP anyway, every other one over HTTPS. No credential is sent over plain HTTP to anything but this machine.

The table is read by consumers and by artefact publish alike, so a producer and its consumers on a self-hosted forge need the same entry.

[artefact]

What gitscale artefact publish ships from this repository: its build output, as one image layer per group of glob patterns.

[[artefact.layer]]
name    = "vendor"
include = ["dist/vendor/**"]

[[artefact.layer]]
name    = "app"
include = ["dist/**"]
exclude = ["**/*.map"]
Key Type Default Meaning
include array of strings — For a single group: the files to ship
exclude array of strings [] For a single group: files to leave out of what include matched
layer array of tables — One table per group, in layer order, each with name, include and an optional exclude. Use either these or include directly, not both

A layer's name is letters, digits, ., _ or -, unique, and recorded as the layer's title. Patterns are plain globs relative to the repository, and a file is stored at its repository path; one that starts with /, contains . or .. components, or does not compile is an error when the config is read. A file goes to the first group that matches it, and a group that matches nothing fails the publish. Every file shipped must be tracked and unmodified at the commit, or ignored — the artefact policy.

This table belongs to the producing repository. A workspace that takes it as an artefact never reads it: what it ships is in the image. How a checkout arrives is no config's to say — see git scale prefer.

[branches]

This repository's long-lived branches, its pinned ones. A pinned branch is built from pins, never a topic; merges into it are gated; and the version tags it holds are the repository's releases.

[branches]
pinned = ["main", "staging", "release/*"]
Key Type Default Meaning
pinned array of strings the remote's default branch (main and master when unknown) Branch names or globs (* matches any run of characters). A written list is exactly what is pinned: the default branch is not implied, and [] makes every branch a topic

Where it is read:

  • In the root: whether the root's branch is a topic, and whether git scale check gates a merge into it.
  • In a dependency, at its default branch: which tags are its releases, for git upgrade. A pin older than the list follows it too.
  • In a dependency, at the revision selected: when the topic's branch is one it pins, what it asks for stays at its pins — see pinned dependencies.

[topic]

How git topic start names topic branches. Read from the root only.

[topic]
prefix = "{user}/"
Key Type Default Meaning
prefix string unset Put in front of every topic branch git topic start creates. {user} is your name for branches: git config gitscale.user, else $USER. Unset, nothing is added or stripped

See branch prefix.

[clean]

Which untracked files git scale clean keeps in this repository.

Key Type Default Meaning
exclude array of strings [] .gitignore-syntax patterns, anchored at this repository's root, passed to git clean -e unchanged
keep_recent string "3months" Root only: how recently an image in the root's image store must have been used to survive the daily prune and git scale gc. A number and a unit: 30d, 2 weeks, 6months

exclude is scoped to the repository whose config it appears in, and nothing below it. A pattern may not be empty or start with -.

[hooks]

Commands GitScale runs after its own operations. Not to be confused with git hooks, which is how GitScale hooks into git.

Key Type Default Meaning
post_sync string — Shell command run at the end of every placement that succeeded, via sh -c in the workspace root. A non-zero exit fails the command
on_pull_error string "fail" under CI, "warn" otherwise What a placement a git hook ran does when it fails: "fail" returns non-zero and fails the git operation, "warn" reports and lets it succeed

Under an installed git hook, post_sync runs only for workspaces on that hook's allowlist.

[forward]

How git commands run across the workspace are run. Read from the root only.

[forward]
parallel = 8
Key Type Default Meaning
parallel integer, at least 1 unset Run git scale fetch, pull and push — after alias lookup — in this many repositories at once. Other git commands run in sequence unless given --parallel

--parallel=N on the command line overrides it; --parallel=1 runs in sequence.

Nested configs

When a checked-out repository carries its own .gitscale.toml and the entry is recursive = true (the default), GitScale reads these from it:

  • [repos] — to resolve transitive dependencies: every entry is a request, resolved with the rest of the workspace, checked out once and linked instead of nested.
  • singleton — whether the repository allows only one checkout of itself.
  • [branches] — which branches it pins: for its dependencies at the revision selected, and for its releases, read by upgrade from its default branch.
  • [clean] — to decide what clean keeps in that repository.

Everything else in a nested config — [resolve], [registries], [artefact], [topic], [hooks], [forward] — is not even parsed by the parent, so nothing in those tables can break it. It belongs to that repository when it is cloned as a workspace root of its own.

Values GitScale refuses to pass to git

.gitscale.toml travels inside the repository, so every value in it arrives from whoever wrote the checked-out branch. Git treats some strings as instructions rather than data, so these are rejected when the config is loaded, by every command:

Rejected Why
url = "ext::sh -c '…'" and any helper:: prefix A remote helper makes git run the rest of the URL as a command — code execution from a repo URL alone, with no [hooks] table in sight. A prefix only counts as a helper when it is a bare word, so an IPv6 literal or a URL that merely contains :: is left alone
A url or revision starting with - It reaches git as a flag, and flags such as --upload-pack= name a program to run
A repo directory that is absolute or contains .. A config must not be able to decide to check out over ~/.ssh
A clean.exclude pattern that is empty or starts with - It reaches git clean -e as an argument

These checks are independent of the hook allowlist, which covers the [hooks] table, and apply even to a placement you started yourself.

Git config keys

Two settings are one person's preference rather than the workspace's, so they are git config, not .gitscale.toml:

Key Meaning
gitscale.user The name {user} stands for in a [topic] prefix. Unset: $USER (USERNAME on Windows)
gitscale.topic.worktree true or false: whether git topic start and switch use a worktree of their own by default. Unset: a worktree when the root is a bare repository — see worktree layout
git config --global gitscale.user andrey
git config --global gitscale.topic.worktree true

Environment variables

Read by GitScale

Variable Effect
CI 1 or true switches to CI behaviour: depth-1 checkouts from the per-user cache, resolution always against the remotes, and git scale clean -fdx of every checkout placed
GITSCALE_CACHE_DIR The CI cache's location
XDG_DATA_HOME $XDG_DATA_HOME/gitscale is the CI cache's location, when GITSCALE_CACHE_DIR is not set
HOME ~/.local/share/gitscale is the last fallback; also where --global hooks are installed
NO_COLOR, TERM NO_COLOR set to anything, or TERM=dumb, turns colour and icons off — see colour
USER, USERNAME The name {user} stands for in a [topic] prefix when gitscale.user is not set
GITSCALE_NO_CI_AUTH Any non-empty value disables CI authentication
GITSCALE_HOOK_ALLOW Set by an installed git hook shim to the allowlist it was installed with. Not something to set yourself
GITSCALE_HOOK Set by GitScale on every git call it makes, so an installed hook does not place the workspace again for it
CI_MERGE_REQUEST_SOURCE_BRANCH_NAME, CI_COMMIT_BRANCH, CI_DEFAULT_BRANCH, CI_MERGE_REQUEST_TARGET_BRANCH_NAME GitLab — the topic of a pipeline, the default branch, and the merge request's target for check
GITHUB_HEAD_REF, GITHUB_REF_NAME, GITHUB_REF_TYPE, GITHUB_BASE_REF, GITHUB_EVENT_PATH GitHub — the same
GITLAB_CI true makes a hook-triggered placement check that the runner's post-checkout clean keeps the declared checkouts, and fail if it would not
GIT_CLEAN_FLAGS GitLab Runner's own: the flags of the git clean it runs after its checkout, default -ffdx. Read for that check, never set by GitScale

CI authentication

Variable Forge
CI_JOB_TOKEN GitLab — presence detects a job
CI_SERVER_URL, or CI_SERVER_HOST + CI_SERVER_PROTOCOL + CI_SERVER_PORT GitLab — the server to authenticate to
GITHUB_ACTIONS GitHub — required runner marker
GITHUB_TOKEN, GH_TOKEN GitHub — the token, first one found
GITHUB_SERVER_URL GitHub — the server, default https://github.com

Artefact registries

Variable Effect
CI_REGISTRY GitLab — the registry the CI server owns: the only one the job token is sent to, and where repositories on the CI server's own host publish
CI_COMMIT_SHA, CI_PROJECT_URL GitLab, with GITLAB_CI=true — the commit and repository artefact publish publishes for
GITHUB_SHA, GITHUB_REPOSITORY GitHub Actions — the same
DOCKER_CONFIG The directory holding Docker's config.json, instead of ~/.docker — for stored logins
REGISTRY_AUTH_FILE Podman's auth file, instead of $XDG_RUNTIME_DIR/containers/auth.json and ~/.config/containers/auth.json

Set by GitScale for git

Every git call GitScale makes runs with GIT_TERMINAL_PROMPT=0 and stdin closed: git never asks at the terminal. Run from a terminal, GitScale's git calls keep your GIT_ASKPASS and SSH_ASKPASS, so they authenticate as your own git in that terminal would — an editor's credential prompt included, such as VS Code's for HTTPS. Where nobody may be watching — a git hook, CI, a run with no terminal — they run with an empty GIT_ASKPASS and SSH_ASKPASS and SSH_ASKPASS_REQUIRE=never: a repository that needs credentials git does not already have, from a credential helper or an ssh agent, fails rather than hangs. The branch deletion git upgrade pushes keeps your helpers either way.

That includes the passphrase of an ssh key: a key that has one must be loaded into an ssh agent (ssh-add). On a machine you reach over SSH, forwarding the agent of the machine you connect from (ForwardAgent yes) works too. When ssh refuses the key, GitScale checks the agent and prints a hint: saying which of these is missing, once for the whole run.


← 2.11 The agent skill · Contents · Next → 4. Command line reference