用 scripts/add-submodule.mts 把外部 Git 仓库挂进本仓的允许根目录(默认 apps / tutorials / skillsets / ai-infra),路径与远程 URL 可由配置文件、CLI 或环境变量覆盖,不必写死在 apps/ 下。
手工 git submodule add 容易:
- 路径写错(越界到未约定的顶层目录)
- 远程 URL 与本仓约定 org/host 不一致
- 忘了在
apps/registry.yaml登记,generate-manifest扫不到
助手脚本统一做三件事:校验路径落在允许根下、推断或采用显式 remote、提示下一步登记 registry。
相关文件:
| 文件 | 作用 |
|---|---|
scripts/submodule.config.json |
默认 org / host / roots / defaultRoot |
scripts/add-submodule.mts |
添加 submodule 的 CLI |
scripts/generate-manifest.mjs |
扫 registry + 技能目录 → data/manifest.json |
apps/registry.yaml |
应用/项目元数据(path 可在任意配置根下) |
更偏 registry 字段说明见 apps/README.md。
路径:scripts/submodule.config.json
{
"org": "variableway",
"host": "github.com",
"defaultRoot": "apps",
"roots": ["apps", "tutorials", "skillsets", "ai-infra"]
}| 字段 | 含义 |
|---|---|
roots |
允许的顶层父目录;--folder / --path 的第一段必须在此列表中 |
defaultRoot |
只传项目名、未指定 --folder 时使用的根(默认 apps) |
org |
未传 --repo 时,推断 URL 的 GitHub org |
host |
未传 --repo 时,推断 URL 的 host(如 github.com) |
优先级(从高到低):CLI 标志 / 对应环境变量 → 配置文件 → 脚本内置默认值。
在仓库根目录执行:
# 默认根 apps/ → apps/<project-name>
# 推断 URL:https://github.com/variableway/<project-name>.git
node scripts/add-submodule.mts <project-name>
# 查看帮助(含当前允许的 roots)
node scripts/add-submodule.mts --help# apps(显式)
node scripts/add-submodule.mts my-app --folder apps
# tutorials
node scripts/add-submodule.mts my-tutorial --folder tutorials
# skillsets
node scripts/add-submodule.mts devops-skill --folder skillsets
# ai-infra
node scripts/add-submodule.mts my-proxy --folder ai-infranode scripts/add-submodule.mts --path skillsets/devops-skill \
--repo https://github.com/qdriven/devops-skill.git--path 必须是 <allowed-root>/<name>(至少两段),且不可含 .. 路径穿越。
# 显式 URL(不再用 org/host 推断)
node scripts/add-submodule.mts my-app --repo https://github.com/acme/my-app.git
# 仍推断路径,但换 org / host
node scripts/add-submodule.mts my-app --folder apps --org acme
node scripts/add-submodule.mts my-app --host github.com --org variableway若目标目录已存在且是 git 仓库,且没有传 --repo,脚本会读取该目录 remote.origin.url,并以 git submodule add --force 挂入。
| 标志 | 说明 |
|---|---|
<project-name> |
位置参数;不可含 /;与 --folder / defaultRoot 组成路径 |
--folder <root> |
父目录,须在 roots 中 |
--path <root/name> |
完整相对路径;与单独传 name 二选一 |
--repo <url> |
显式 git remote |
--org <org> |
覆盖推断用 org |
--host <host> |
覆盖推断用 host |
-h / --help |
打印用法与当前允许 roots |
| 变量 | 对应配置 |
|---|---|
SUBMODULE_ORG |
org |
SUBMODULE_HOST |
host |
SUBMODULE_DEFAULT_ROOT |
defaultRoot |
SUBMODULE_ROOTS |
roots(逗号分隔,如 apps,tutorials,skillsets) |
示例:
SUBMODULE_ORG=acme SUBMODULE_DEFAULT_ROOT=tutorials \
node scripts/add-submodule.mts demo-course| 变量 | 默认 | 说明 |
|---|---|---|
MANIFEST_REGISTRY |
apps/registry.yaml |
相对仓库根的 registry 路径 |
MANIFEST_OUT |
data/manifest.json |
输出路径 |
MANIFEST_SKILLS_DIRS |
(自动) | 逗号分隔的技能扫描目录;未设时扫描 skills/ 与配置里已存在的 roots |
配置文件的 roots 也会写入 manifest 的 config.submoduleRoots,便于 showcase 站点读取。
node scripts/generate-manifest.mjs
MANIFEST_OUT=tmp/manifest.json node scripts/generate-manifest.mjs添加 submodule 后,若希望出现在 manifest / 门户列表里,在 apps/registry.yaml 增加条目,path 写成真实落盘路径(不必仍以 apps/ 开头):
apps:
- name: devops-skill
title: DevOps Skill
path: skillsets/devops-skill # 任意配置根下均可
source: submodule
repo: https://github.com/qdriven/devops-skill.git
visibility: public
status: activesource: local 表示代码直接在本仓;submodule 表示独立远程仓库。字段说明见 apps/README.md。
| 现象 | 原因 / 处理 |
|---|---|
folder "…" is not allowed |
--folder 不在 roots / SUBMODULE_ROOTS 中;改配置或换合法根 |
--path must be under an allowed root |
路径顶层段不在允许列表,或含 .. / 绝对路径 |
--path must include <root>/<project-name> |
--path 只有一段(如 apps),需 apps/foo |
project name must not contain path separators |
位置参数里写了 tutorials/foo;改用 --folder 或 --path |
git submodule add 失败 |
远程不存在、权限不足、或路径已被占用;检查 URL 与 .gitmodules |
| 加了 submodule 但 manifest 没有 | 未在 apps/registry.yaml 登记,或未跑 generate-manifest.mjs |
# 1. 按需改 scripts/submodule.config.json(或用 env)
# 2. 添加
node scripts/add-submodule.mts my-tool --folder tutorials
# 3. 在 apps/registry.yaml 登记 path / source / repo
# 4. 更新 manifest
node scripts/generate-manifest.mjs
# 5. 提交:.gitmodules、子模块指针、registry(及 manifest,若纳入版本控制)允许根由
submodule.config.json决定;助手只往这些根下挂 submodule。
URL 默认同 org/host 推断,可用--repo或已有 clone 的 origin 覆盖。
挂完还要在apps/registry.yaml写对path,manifest 才会看到。
- apps/README.md — registry 字段与 local / submodule 约定
- Git Worktree 如何工作 — 并行分支隔离检出
git submodule --help/ Git Tools - Submodules