gkit clone
Clone the repos listed in a conf file. Existing repos are skipped. Every git
command is printed (transparency); all subprocess output is captured so a noisy
.envrc can’t distort it.
Synopsis
gkit clone <conf…> [--user-name <n>] [--user-email <e>] [--no-submodule-branch] [--no-direnv]
conf… are explicit conf file(s) — at least one is required, and a directory
is not accepted (use a shell glob for “every conf here”):
gkit clone example-org.toml acme.toml # explicit list
gkit clone *.toml # every conf in the cwd (shell glob)
gkit clone confs/*.toml # every conf in confs/ (shell glob)
gkit clone with no file — or with a directory like gkit clone confs/ — is an
error. This matches how logoff --conf takes confs. When several
confs are given they’re processed in turn (with a == <conf> == header); each has
its own host/namespace. A conf that fails to parse is reported and skipped; the
rest still run and the exit code is non-zero if anything failed.
What it does, per repo
- Build and print
git <git-flags> clone [tokens] --recurse-submodules <clone-flags> <-- flags> <url> <dir>. - Skip if the directory already exists; otherwise clone (output captured).
- Git identity →
git config user.name/user.emailon the repo and every submodule (recursive — a submodule is its own repo with its own config), if resolved (see below; printed, since the values are your explicit input). - Submodules → init + switch each onto its
.gitmodulesbranch (--no-submodule-branchto skip). .envrc→direnv allow(trust-only, no evaluation;--no-direnvto skip).
Git identity (--user-name / --user-email)
Identity is per-invocation, never in the conf — the conf is shared across a team, so writing one person’s name/email into it would stamp everyone’s clones. Instead you supply it when you run the command:
- pass
--user-name/--user-email, or - omit them and gkit prompts (in a terminal), defaulting to your current
git config user.name/user.email(Enter keeps the default; empty with no default skips that field).
With no flag and no terminal (e.g. CI) the field is left unset, so the clone inherits your global git identity — the command never hangs waiting for input.
The resolved identity is applied to the superproject and recursively to every submodule (each is a separate repo, so commits there use the same identity rather than your global one).
The resolved values are also exported to hooks as $GKIT_USER_NAME /
$GKIT_USER_EMAIL (empty when unset).
Flags
| Flag | Effect |
|---|---|
--user-name <n> | git config user.name to stamp on each cloned repo (prompted if omitted in a terminal). |
--user-email <e> | git config user.email to stamp on each cloned repo (prompted if omitted in a terminal). |
--no-submodule-branch | Leave submodules detached (don’t switch to their branch). |
--no-direnv | Don’t direnv allow repos that have an .envrc. |
Per-repo customization (depth, branch, clone-flags), global
git-flags/clone-flags, and pre-clone/post-clone hooks live in the
conf file. The full step order (global/repo pre → clone →
built-ins → global/repo post) is documented there.
Example
host = "tlbb"
namespace = "example-org"
clone-flags = ["--filter=blob:none"]
[[repo]]
dir = "$HOME/work/cosp"
branch = "dev"
clone-flags = ["--no-tags"]
post-clone = ["echo done $GKIT_REPO"]
$ gkit clone repos.toml --user-name "Jane Dev" --user-email jane@example-org.com
+ git clone --branch dev --single-branch --recurse-submodules --filter=blob:none --no-tags tlbb:example-org/cosp.git /Users/you/work/cosp
+ git config user.name Jane Dev
+ git config user.email jane@example-org.com
+ git submodule foreach --recursive git config user.name 'Jane Dev'; git config user.email 'jane@example-org.com'
+ echo done $GKIT_REPO
done cosp
cloned cosp /Users/you/work/cosp