@aipper/aiws-spec 0.0.12 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/templates/workspace/.agents/skills/ws-deliver/SKILL.md +22 -1
- package/templates/workspace/.agents/skills/ws-finish/SKILL.md +46 -23
- package/templates/workspace/.agents/skills/ws-preflight/SKILL.md +3 -0
- package/templates/workspace/.agents/skills/ws-pull/SKILL.md +4 -3
- package/templates/workspace/.agents/skills/ws-push/SKILL.md +105 -0
- package/templates/workspace/.agents/skills/ws-submodule-setup/SKILL.md +65 -0
- package/templates/workspace/.claude/commands/ws-deliver.md +1 -1
- package/templates/workspace/.claude/commands/ws-finish.md +25 -6
- package/templates/workspace/.claude/commands/ws-pull.md +2 -2
- package/templates/workspace/.claude/commands/ws-push.md +90 -0
- package/templates/workspace/.claude/commands/ws-submodule-setup.md +54 -0
- package/templates/workspace/.iflow/commands/ws-deliver.toml +1 -1
- package/templates/workspace/.iflow/commands/ws-finish.toml +6 -5
- package/templates/workspace/.iflow/commands/ws-pull.toml +1 -0
- package/templates/workspace/.iflow/commands/ws-push.toml +40 -0
- package/templates/workspace/.iflow/commands/ws-submodule-setup.toml +32 -0
- package/templates/workspace/.opencode/command/ws-deliver.md +1 -0
- package/templates/workspace/.opencode/command/ws-finish.md +25 -6
- package/templates/workspace/.opencode/command/ws-pull.md +2 -2
- package/templates/workspace/.opencode/command/ws-push.md +93 -0
- package/templates/workspace/.opencode/command/ws-submodule-setup.md +57 -0
- package/templates/workspace/AGENTS.md +1 -1
- package/templates/workspace/manifest.json +14 -0
package/package.json
CHANGED
|
@@ -27,6 +27,26 @@ description: 交付(submodules + superproject 分步提交,并安全合并
|
|
|
27
27
|
|
|
28
28
|
建议流程(按顺序):
|
|
29
29
|
|
|
30
|
+
## 0) submodule branch 真值检查(减少 detached 与人为差异)
|
|
31
|
+
如果存在 `.gitmodules` 但缺少 `submodule.<name>.branch`,先运行 `$ws-submodule-setup` 并提交 `.gitmodules`,否则后续 `aiws validate .` 会失败,且 `ws-pull/ws-finish` 无法确定性工作。
|
|
32
|
+
```bash
|
|
33
|
+
if [[ -f .gitmodules ]]; then
|
|
34
|
+
missing=0
|
|
35
|
+
while read -r key sub_path; do
|
|
36
|
+
name="${key#submodule.}"; name="${name%.path}"
|
|
37
|
+
b="$(git config --file .gitmodules --get "submodule.${name}.branch" 2>/dev/null || true)"
|
|
38
|
+
if [[ -z "${b:-}" ]]; then
|
|
39
|
+
echo "error: missing .gitmodules submodule.${name}.branch (path=${sub_path})"
|
|
40
|
+
missing=1
|
|
41
|
+
fi
|
|
42
|
+
done < <(git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$' 2>/dev/null || true)
|
|
43
|
+
if [[ "$missing" -ne 0 ]]; then
|
|
44
|
+
echo "hint: run $ws-submodule-setup (and commit .gitmodules), then retry"
|
|
45
|
+
exit 2
|
|
46
|
+
fi
|
|
47
|
+
fi
|
|
48
|
+
```
|
|
49
|
+
|
|
30
50
|
## A) 发现 submodules 清单(数量不固定)
|
|
31
51
|
在 superproject 根目录执行:
|
|
32
52
|
```bash
|
|
@@ -43,7 +63,8 @@ git -C "$sub_path" branch --show-current
|
|
|
43
63
|
git -C "$sub_path" status --porcelain
|
|
44
64
|
```
|
|
45
65
|
2) 若 submodule 处于 detached HEAD(`branch --show-current` 为空):
|
|
46
|
-
-
|
|
66
|
+
- 说明:这通常是因为 superproject 的 gitlink checkout(例如 `git submodule update`)导致 detached。
|
|
67
|
+
- 若你要在该 submodule 里提交:在 submodule 内创建并切到同名 change 分支(与 superproject 对齐),例如 `change/<change-id>`:
|
|
47
68
|
```bash
|
|
48
69
|
git -C "$sub_path" switch -c "change/<change-id>"
|
|
49
70
|
```
|
|
@@ -15,8 +15,27 @@ description: 收尾(门禁 + 安全合并 + submodule→主仓库顺序 push
|
|
|
15
15
|
- 工作区是干净的:`git status --porcelain` 无输出(若有未提交改动:先 commit 或 stash)
|
|
16
16
|
- change 分支已存在:`change/<change-id>`(也支持 `changes/`、`ws/`、`ws-change/`)
|
|
17
17
|
- 若使用 worktree:在“目标分支所在 worktree”执行(`aiws change finish` 会提示正确的 worktree)
|
|
18
|
+
- 若存在 `.gitmodules`:必须为每个 submodule 配置 `submodule.<name>.branch`(否则无法确定性减少 detached;先运行 `$ws-submodule-setup` 并提交 `.gitmodules`)
|
|
18
19
|
|
|
19
20
|
建议步骤:
|
|
21
|
+
0) 若存在 `.gitmodules`,先检查 submodule branch 配置是否齐全(缺失则停止并提示 setup):
|
|
22
|
+
```bash
|
|
23
|
+
if [[ -f .gitmodules ]]; then
|
|
24
|
+
missing=0
|
|
25
|
+
while read -r key sub_path; do
|
|
26
|
+
name="${key#submodule.}"; name="${name%.path}"
|
|
27
|
+
b="$(git config --file .gitmodules --get "submodule.${name}.branch" 2>/dev/null || true)"
|
|
28
|
+
if [[ -z "${b:-}" ]]; then
|
|
29
|
+
echo "error: missing .gitmodules submodule.${name}.branch (path=${sub_path})"
|
|
30
|
+
missing=1
|
|
31
|
+
fi
|
|
32
|
+
done < <(git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$' 2>/dev/null || true)
|
|
33
|
+
if [[ "$missing" -ne 0 ]]; then
|
|
34
|
+
echo "hint: run $ws-submodule-setup (and commit .gitmodules), then retry"
|
|
35
|
+
exit 2
|
|
36
|
+
fi
|
|
37
|
+
fi
|
|
38
|
+
```
|
|
20
39
|
1) (推荐)先跑一次门禁并落盘证据:
|
|
21
40
|
```bash
|
|
22
41
|
if [[ -x "./node_modules/.bin/aiws" ]]; then
|
|
@@ -49,39 +68,43 @@ base_branch="$(git branch --show-current)"
|
|
|
49
68
|
git config --file .gitmodules --get-regexp '^submodule\..*\.path$' 2>/dev/null || true
|
|
50
69
|
|
|
51
70
|
# 对每个 submodule.<name>.path <sub_path>:
|
|
52
|
-
#
|
|
71
|
+
# 说明:`git submodule update` 会把 submodule checkout 到固定 gitlink commit,导致 detached HEAD。
|
|
72
|
+
# 为减少“游离状态”的协作摩擦,本步骤采用“pin 分支”策略:
|
|
73
|
+
# - 仅在 `.gitmodules` 明确配置了 `submodule.<name>.branch` 时执行(避免 origin 多分支导致误判)
|
|
74
|
+
# - 不改动 submodule 现有分支指针(例如不强行移动 main/master)
|
|
75
|
+
# - 创建/更新本地 pin 分支:`aiws/pin/<target_branch>` 指向 gitlink commit,并将其 upstream 设为 `origin/<target_branch>`
|
|
53
76
|
sub_sha="$(git rev-parse "HEAD:<sub_path>")"
|
|
54
|
-
# 2) 推断目标分支(优先:.gitmodules 的 submodule.<name>.branch;否则 origin/HEAD;否则 main/master)
|
|
55
77
|
cfg_branch="$(git config --file .gitmodules --get "submodule.<name>.branch" 2>/dev/null || true)"
|
|
56
78
|
if [[ "${cfg_branch:-}" == "." ]]; then cfg_branch="$base_branch"; fi
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if git -C "<sub_path>" show-ref --verify --quiet refs/heads/main || git -C "<sub_path>" show-ref --verify --quiet refs/remotes/origin/main; then
|
|
61
|
-
target_branch="main"
|
|
62
|
-
else
|
|
63
|
-
target_branch="master"
|
|
64
|
-
fi
|
|
79
|
+
if [[ -z "${cfg_branch:-}" ]]; then
|
|
80
|
+
echo "[warn] <sub_path>: missing .gitmodules submodule.<name>.branch; keep detached and skip auto-push"
|
|
81
|
+
continue
|
|
65
82
|
fi
|
|
83
|
+
target_branch="$cfg_branch"
|
|
84
|
+
pin_branch="aiws/pin/${target_branch}"
|
|
66
85
|
|
|
67
|
-
|
|
68
|
-
git -C "<sub_path>"
|
|
69
|
-
|
|
86
|
+
git -C "<sub_path>" fetch origin --prune
|
|
87
|
+
if ! git -C "<sub_path>" show-ref --verify --quiet "refs/remotes/origin/${target_branch}"; then
|
|
88
|
+
echo "[warn] <sub_path>: origin/${target_branch} not found; keep detached and skip auto-push"
|
|
89
|
+
continue
|
|
90
|
+
fi
|
|
70
91
|
|
|
71
|
-
#
|
|
72
|
-
git -C "<sub_path>"
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
else
|
|
76
|
-
git -C "<sub_path>" merge --ff-only "$sub_sha"
|
|
92
|
+
# 仅当 gitlink commit 属于 origin/<target_branch> 的历史时才“挂回分支”
|
|
93
|
+
if ! git -C "<sub_path>" merge-base --is-ancestor "${sub_sha}" "origin/${target_branch}"; then
|
|
94
|
+
echo "[warn] <sub_path>: ${sub_sha} is not in origin/${target_branch}; keep detached and stop (need manual reconcile)"
|
|
95
|
+
exit 1
|
|
77
96
|
fi
|
|
78
97
|
|
|
79
|
-
|
|
80
|
-
git -C "<sub_path>"
|
|
98
|
+
git -C "<sub_path>" checkout -B "${pin_branch}" "${sub_sha}"
|
|
99
|
+
git -C "<sub_path>" branch --set-upstream-to "origin/${target_branch}" "${pin_branch}" >/dev/null 2>&1 || true
|
|
100
|
+
git -C "<sub_path>" status -sb
|
|
101
|
+
|
|
102
|
+
# push:只允许 fast-forward(若远端分叉会被拒绝;此时必须人工处理)
|
|
103
|
+
git -C "<sub_path>" push origin "${sub_sha}:refs/heads/${target_branch}"
|
|
81
104
|
```
|
|
82
105
|
规则:
|
|
83
|
-
- 每个 submodule
|
|
84
|
-
- 若任一 submodule
|
|
106
|
+
- 每个 submodule 必须先执行“pin 分支挂回 + fast-forward push”,再 push 主仓库。
|
|
107
|
+
- 若任一 submodule 的 gitlink commit 不在 `origin/<target_branch>` 历史中:立即停止,先人工处理分叉,再继续。
|
|
85
108
|
|
|
86
109
|
5) 仅当 submodules 全部成功后,再 push superproject 当前分支:
|
|
87
110
|
```bash
|
|
@@ -23,6 +23,9 @@ description: 预检(提交前快速检查与建议)
|
|
|
23
23
|
- `Found:` <实际读取到的文件列表>
|
|
24
24
|
- `Missing:` <缺失文件列表>
|
|
25
25
|
- `Key rules:` 3–8 条 bullet(范围/禁止项/必须产物/必须验证命令)
|
|
26
|
+
5) 若存在 `.gitmodules`:
|
|
27
|
+
- 输出 submodule 列表:`git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$'`
|
|
28
|
+
- 检查每个 submodule 是否配置 `submodule.<name>.branch`(缺失则提示先运行 `$ws-submodule-setup`;否则 `aiws validate .` 会失败)
|
|
26
29
|
|
|
27
30
|
安全:
|
|
28
31
|
- 不打印 secrets;遇到疑似敏感值只提示“存在风险”但不要复述原文。
|
|
@@ -13,7 +13,7 @@ description: 拉取并对齐 submodules(避免 detached;减少人为差异
|
|
|
13
13
|
- 安全拉取 superproject(默认只允许 fast-forward)
|
|
14
14
|
- 初始化/同步 submodules(`--init --recursive`)
|
|
15
15
|
- 在**不改动 superproject gitlink commit** 的前提下,尽量把每个 submodule 从 detached HEAD “挂回”到一个**确定的目标分支**(仅当该分支包含 gitlink commit 时)
|
|
16
|
-
-
|
|
16
|
+
- 若未配置 `.gitmodules` 的 `submodule.<name>.branch`:保持 detached,并提示先运行 `$ws-submodule-setup`
|
|
17
17
|
|
|
18
18
|
安全约束(强制):
|
|
19
19
|
- 不执行破坏性命令(不 `reset --hard` 主仓库;不改动远端)
|
|
@@ -50,7 +50,7 @@ fi
|
|
|
50
50
|
说明:
|
|
51
51
|
- 该步骤不会改变 superproject 的 gitlink commit(也不会让主仓库出现“submodule modified”)。
|
|
52
52
|
- 只在目标分支包含该 gitlink commit 时才执行“挂回”;否则保持 detached 并提示原因。
|
|
53
|
-
- 为了避免 origin 分支较多时“猜错分支”,本步骤**只在** `.gitmodules` 明确配置了 `submodule.<name>.branch` 时才执行“挂回分支”;否则保持 detached
|
|
53
|
+
- 为了避免 origin 分支较多时“猜错分支”,本步骤**只在** `.gitmodules` 明确配置了 `submodule.<name>.branch` 时才执行“挂回分支”;否则保持 detached 并提示先运行 `$ws-submodule-setup` 对齐配置。
|
|
54
54
|
|
|
55
55
|
```bash
|
|
56
56
|
if [[ -f .gitmodules ]]; then
|
|
@@ -71,7 +71,7 @@ if [[ -f .gitmodules ]]; then
|
|
|
71
71
|
cfg_branch="$(git config --file .gitmodules --get "submodule.${name}.branch" 2>/dev/null || true)"
|
|
72
72
|
if [[ "${cfg_branch:-}" == "." ]]; then cfg_branch="$base_branch"; fi
|
|
73
73
|
if [[ -z "${cfg_branch:-}" ]]; then
|
|
74
|
-
echo "[warn] ${sub_path}: missing .gitmodules submodule.${name}.branch; keep detached (run
|
|
74
|
+
echo "[warn] ${sub_path}: missing .gitmodules submodule.${name}.branch; keep detached (run ws-submodule-setup to set it)"
|
|
75
75
|
continue
|
|
76
76
|
fi
|
|
77
77
|
|
|
@@ -112,6 +112,7 @@ git commit -m "chore(submodule): set tracking branch"
|
|
|
112
112
|
建议:
|
|
113
113
|
- 只有当团队明确希望“子模块按分支滚动”(而不是锁定固定 commit)时,才采用方案 2。
|
|
114
114
|
- 若只是想避免 detached 但仍锁定 gitlink commit:优先使用步骤 3(不改 `.gitmodules`)。
|
|
115
|
+
- 推荐用 `$ws-submodule-setup` 交互式对齐所有 submodules 的 branch,并提交 `.gitmodules`。
|
|
115
116
|
|
|
116
117
|
输出要求:
|
|
117
118
|
- `Context:` 当前分支 + 是否存在 `.gitmodules` + submodule 列表
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ws-push
|
|
3
|
+
description: 推送(submodule 感知:先 submodules 后 superproject;fast-forward 安全)
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
用中文输出(命令/路径/代码标识符保持原样不翻译)。
|
|
7
|
+
|
|
8
|
+
目标:
|
|
9
|
+
- 在不自动提交的前提下,安全 push 当前仓库
|
|
10
|
+
- 若仓库包含 submodules:按 `submodules -> superproject` 顺序 push,减少“别人拉取后子模块 detached/分叉”的协作摩擦
|
|
11
|
+
- 若不包含 submodules:按普通 git 仓库的规则 push
|
|
12
|
+
|
|
13
|
+
安全约束(强制):
|
|
14
|
+
- 不自动提交、不自动 `git add -A`
|
|
15
|
+
- 不使用 `--force` / `--force-with-lease`
|
|
16
|
+
- 默认只允许 fast-forward push(发现分叉则停止并提示人工处理)
|
|
17
|
+
- 若工作区不干净:停止并要求先 commit 或 stash
|
|
18
|
+
|
|
19
|
+
执行步骤(建议):
|
|
20
|
+
0) 输出上下文:
|
|
21
|
+
```bash
|
|
22
|
+
git branch --show-current
|
|
23
|
+
git status --porcelain
|
|
24
|
+
git status -sb
|
|
25
|
+
```
|
|
26
|
+
若 `git status --porcelain` 非空:停止。
|
|
27
|
+
|
|
28
|
+
1) 判断是否存在 submodules:
|
|
29
|
+
```bash
|
|
30
|
+
if [[ -f .gitmodules ]]; then
|
|
31
|
+
git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$' || true
|
|
32
|
+
else
|
|
33
|
+
echo "[info] no .gitmodules"
|
|
34
|
+
fi
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
2) 若不存在 `.gitmodules` 或没有 submodule 条目:按普通仓库 push(仍需用户确认):
|
|
38
|
+
```bash
|
|
39
|
+
git remote -v
|
|
40
|
+
git push
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
3) 若存在 submodules:先检查 `.gitmodules` 的 branch 真值是否齐全(缺失则停止并提示 setup):
|
|
44
|
+
```bash
|
|
45
|
+
missing=0
|
|
46
|
+
while read -r key sub_path; do
|
|
47
|
+
name="${key#submodule.}"; name="${name%.path}"
|
|
48
|
+
b="$(git config --file .gitmodules --get "submodule.${name}.branch" 2>/dev/null || true)"
|
|
49
|
+
if [[ -z "${b:-}" ]]; then
|
|
50
|
+
echo "error: missing .gitmodules submodule.${name}.branch (path=${sub_path})"
|
|
51
|
+
missing=1
|
|
52
|
+
fi
|
|
53
|
+
done < <(git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$' 2>/dev/null || true)
|
|
54
|
+
if [[ "$missing" -ne 0 ]]; then
|
|
55
|
+
echo "hint: run $ws-submodule-setup (and commit .gitmodules), then retry"
|
|
56
|
+
exit 2
|
|
57
|
+
fi
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
4) 逐个 push submodules(fast-forward only),再 push superproject:
|
|
61
|
+
```bash
|
|
62
|
+
base_branch="$(git branch --show-current)"
|
|
63
|
+
|
|
64
|
+
git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$' 2>/dev/null \
|
|
65
|
+
| while read -r key sub_path; do
|
|
66
|
+
name="${key#submodule.}"; name="${name%.path}"
|
|
67
|
+
echo "== submodule: ${sub_path} (${name}) =="
|
|
68
|
+
|
|
69
|
+
# submodule 工作区必须干净
|
|
70
|
+
if [[ -n "$(git -C "${sub_path}" status --porcelain 2>/dev/null || true)" ]]; then
|
|
71
|
+
echo "error: submodule dirty: ${sub_path}"
|
|
72
|
+
exit 2
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
cfg_branch="$(git config --file .gitmodules --get "submodule.${name}.branch" 2>/dev/null || true)"
|
|
76
|
+
if [[ "${cfg_branch:-}" == "." ]]; then cfg_branch="$base_branch"; fi
|
|
77
|
+
target_branch="${cfg_branch}"
|
|
78
|
+
|
|
79
|
+
git -C "${sub_path}" fetch origin --prune
|
|
80
|
+
if ! git -C "${sub_path}" show-ref --verify --quiet "refs/remotes/origin/${target_branch}"; then
|
|
81
|
+
echo "error: missing origin/${target_branch} for ${sub_path}"
|
|
82
|
+
exit 2
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# fast-forward only: origin/<branch> 必须是 HEAD 的祖先
|
|
86
|
+
if ! git -C "${sub_path}" merge-base --is-ancestor "origin/${target_branch}" HEAD; then
|
|
87
|
+
echo "error: non-fast-forward (submodule=${sub_path}, branch=${target_branch})"
|
|
88
|
+
echo "hint: rebase/merge in submodule, then retry"
|
|
89
|
+
exit 2
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
# push HEAD -> origin/<branch>(不 force)
|
|
93
|
+
git -C "${sub_path}" push origin "HEAD:refs/heads/${target_branch}"
|
|
94
|
+
done
|
|
95
|
+
|
|
96
|
+
# 最后 push superproject(仍需用户确认远端/分支)
|
|
97
|
+
git remote -v
|
|
98
|
+
git push
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
输出要求:
|
|
102
|
+
- `Context:` 当前分支 + 是否有 submodules
|
|
103
|
+
- `Submodules:` 每个 submodule push 的目标分支与结果(成功/阻断原因)
|
|
104
|
+
- `Superproject:` push 结果
|
|
105
|
+
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ws-submodule-setup
|
|
3
|
+
description: 子模块分支对齐(写入 .gitmodules 的 submodule.<name>.branch;减少 detached 与人为差异)
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
用中文输出(命令/路径/代码标识符保持原样不翻译)。
|
|
7
|
+
|
|
8
|
+
目标:
|
|
9
|
+
- 为每个 submodule 写入 `.gitmodules` 的 `submodule.<name>.branch`,让 `ws-pull` / `ws-finish` 能确定性地“挂回分支/fast-forward push”,避免 origin 多分支时靠猜导致偏差。
|
|
10
|
+
- 该变更是 **superproject 的团队真值**:需要提交 `.gitmodules`。
|
|
11
|
+
|
|
12
|
+
安全约束(强制):
|
|
13
|
+
- 不自动提交、不自动 push(必须先输出 diff 并让用户确认)
|
|
14
|
+
- 不在 submodule 中做破坏性操作(不 `reset --hard` / 不改动远端)
|
|
15
|
+
|
|
16
|
+
步骤(建议):
|
|
17
|
+
1) 确认工作区干净(否则停止):
|
|
18
|
+
```bash
|
|
19
|
+
git status --porcelain
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
2) 列出 submodules(没有则停止并说明无需配置):
|
|
23
|
+
```bash
|
|
24
|
+
test -f .gitmodules || { echo "no .gitmodules"; exit 0; }
|
|
25
|
+
git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$'
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
3) 对每个 submodule,输出当前配置与建议分支(让用户确认每个 submodule 的 branch):
|
|
29
|
+
```bash
|
|
30
|
+
while read -r key sub_path; do
|
|
31
|
+
name="${key#submodule.}"; name="${name%.path}"
|
|
32
|
+
echo "== submodule: ${name} path=${sub_path} =="
|
|
33
|
+
echo "[current] branch=$(git config --file .gitmodules --get submodule.${name}.branch || true)"
|
|
34
|
+
echo "[origin] HEAD=$(git -C \"${sub_path}\" symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null || true)"
|
|
35
|
+
git -C "${sub_path}" branch -r --list "origin/*" | sed -n '1,30p' || true
|
|
36
|
+
echo "[choose] set one of:"
|
|
37
|
+
echo " - a concrete branch, e.g. main / master / release/x.y"
|
|
38
|
+
echo " - '.' to follow superproject current branch name (only if your team uses matching branch names)"
|
|
39
|
+
done < <(git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$')
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
4) 逐个写入分支配置(每次写完都回显,避免误配):
|
|
43
|
+
```bash
|
|
44
|
+
# Example:
|
|
45
|
+
# git submodule set-branch --branch main path/to/submodule
|
|
46
|
+
# git submodule set-branch --branch . path/to/submodule
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
5) 输出变更并让用户确认是否提交:
|
|
50
|
+
```bash
|
|
51
|
+
git diff -- .gitmodules
|
|
52
|
+
git status --porcelain
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
6) 若用户确认要提交:
|
|
56
|
+
```bash
|
|
57
|
+
git add .gitmodules
|
|
58
|
+
git commit -m "chore(submodule): set tracking branches"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
输出要求:
|
|
62
|
+
- `Submodules:` name/path + 选择的 branch(每个都列出)
|
|
63
|
+
- `Diff:` `.gitmodules` 的 diff(或至少 `git diff -- .gitmodules` 的摘要)
|
|
64
|
+
- `Next:` 提示后续用 `$ws-pull` 拉取可自动减少 detached;`aiws validate` 会检查该配置是否齐全
|
|
65
|
+
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
建议流程(按顺序):
|
|
17
17
|
1) 先运行 `/ws-preflight`。
|
|
18
|
+
2) 如果存在 `.gitmodules` 但缺少 `submodule.<name>.branch`,先运行 `/ws-submodule-setup` 并提交 `.gitmodules`(否则 `aiws validate .` 会失败,且 submodule 工作流会产生人为差异)。
|
|
18
19
|
2) 发现 submodules:
|
|
19
20
|
- `git submodule status --recursive`
|
|
20
21
|
3) 逐个提交 submodules(按上一步顺序):
|
|
@@ -42,4 +43,3 @@
|
|
|
42
43
|
<!-- AIWS_MANAGED_END:claude:ws-deliver -->
|
|
43
44
|
|
|
44
45
|
可在下方追加本项目对 Claude Code 的额外说明(托管块外内容会被保留)。
|
|
45
|
-
|
|
@@ -9,23 +9,42 @@
|
|
|
9
9
|
前置(必须):
|
|
10
10
|
- 工作区干净:`git status --porcelain` 无输出(否则先 commit 或 stash)
|
|
11
11
|
- change 分支存在(`change/<change-id>`;也支持 `changes/`、`ws/`、`ws-change/`)
|
|
12
|
+
- 若存在 `.gitmodules`:必须为每个 submodule 配置 `submodule.<name>.branch`(否则先运行 `/ws-submodule-setup` 并提交 `.gitmodules`)
|
|
12
13
|
|
|
13
14
|
步骤(建议):
|
|
15
|
+
0) 若存在 `.gitmodules`,先检查 submodule branch 配置是否齐全(缺失则停止并提示 setup):
|
|
16
|
+
```bash
|
|
17
|
+
if [[ -f .gitmodules ]]; then
|
|
18
|
+
missing=0
|
|
19
|
+
while read -r key sub_path; do
|
|
20
|
+
name="${key#submodule.}"; name="${name%.path}"
|
|
21
|
+
b="$(git config --file .gitmodules --get "submodule.${name}.branch" 2>/dev/null || true)"
|
|
22
|
+
if [[ -z "${b:-}" ]]; then
|
|
23
|
+
echo "error: missing .gitmodules submodule.${name}.branch (path=${sub_path})"
|
|
24
|
+
missing=1
|
|
25
|
+
fi
|
|
26
|
+
done < <(git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$' 2>/dev/null || true)
|
|
27
|
+
if [[ "$missing" -ne 0 ]]; then
|
|
28
|
+
echo "hint: run /ws-submodule-setup (and commit .gitmodules), then retry"
|
|
29
|
+
exit 2
|
|
30
|
+
fi
|
|
31
|
+
fi
|
|
32
|
+
```
|
|
14
33
|
1) 先运行 `/ws-preflight`(确保真值文件齐全)。
|
|
15
34
|
2) (推荐)门禁校验并落盘证据:`aiws validate . --stamp`(未安装全局 aiws 时可用 `npx @aipper/aiws validate . --stamp`)。
|
|
16
35
|
3) 安全合并并切回目标分支:
|
|
17
36
|
- 若当前就在 `change/<change-id>` 分支上,可直接执行:`aiws change finish`
|
|
18
37
|
- 否则执行:`aiws change finish <change-id>`
|
|
19
38
|
4) 若提示无法 fast-forward:先在 change 分支(或对应 worktree)里 `git rebase <target-branch>`,再重试 `aiws change finish`。
|
|
20
|
-
5) 合并成功后,按顺序处理每个 submodule
|
|
39
|
+
5) 合并成功后,按顺序处理每个 submodule(减少 detached;再 push):
|
|
21
40
|
- 发现 submodules:`git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$'`
|
|
22
41
|
- 对每个 `<sub_path>`:
|
|
23
42
|
- 读取 superproject 当前 gitlink:`git rev-parse "HEAD:<sub_path>"`
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
- push
|
|
28
|
-
6) 任一 submodule
|
|
43
|
+
- 目标分支:必须在 `.gitmodules` 配置 `submodule.<name>.branch`(若为 `.` 则用当前主仓库分支;避免 origin 多分支时误判)
|
|
44
|
+
- 用 pin 分支挂回(不改动现有 main/master 指针):`git -C "<sub_path>" checkout -B "aiws/pin/<target-branch>" <gitlink-sha>`
|
|
45
|
+
- 仅当 `<gitlink-sha>` 属于 `origin/<target-branch>` 历史时才允许 push;否则停止并人工处理分叉
|
|
46
|
+
- push(只允许 fast-forward):`git -C "<sub_path>" push origin "<gitlink-sha>:refs/heads/<target-branch>"`
|
|
47
|
+
6) 任一 submodule 不满足 fast-forward 条件时立即停止(不要继续 push 主仓库)。
|
|
29
48
|
7) submodules 全部成功后,再 push 主仓库当前分支:
|
|
30
49
|
- `git branch --show-current`
|
|
31
50
|
- `git status -sb`
|
|
@@ -36,7 +36,7 @@ fi
|
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
4) (可选但推荐)把 submodule 从 detached HEAD 尽量“挂回分支”(不改动 gitlink commit):
|
|
39
|
-
为避免 origin 多分支时“猜错分支”,本步骤只在 `.gitmodules` 明确配置了 `submodule.<name>.branch` 时才执行;否则保持 detached
|
|
39
|
+
为避免 origin 多分支时“猜错分支”,本步骤只在 `.gitmodules` 明确配置了 `submodule.<name>.branch` 时才执行;否则保持 detached 并提示先运行 `/ws-submodule-setup` 对齐配置。
|
|
40
40
|
```bash
|
|
41
41
|
if [[ -f .gitmodules ]]; then
|
|
42
42
|
base_branch="$(git branch --show-current)"
|
|
@@ -51,7 +51,7 @@ if [[ -f .gitmodules ]]; then
|
|
|
51
51
|
cfg_branch="$(git config --file .gitmodules --get "submodule.${name}.branch" 2>/dev/null || true)"
|
|
52
52
|
if [[ "${cfg_branch:-}" == "." ]]; then cfg_branch="$base_branch"; fi
|
|
53
53
|
if [[ -z "${cfg_branch:-}" ]]; then
|
|
54
|
-
echo "[warn] ${sub_path}: missing .gitmodules submodule.${name}.branch; keep detached"
|
|
54
|
+
echo "[warn] ${sub_path}: missing .gitmodules submodule.${name}.branch; keep detached (run ws-submodule-setup)"
|
|
55
55
|
continue
|
|
56
56
|
fi
|
|
57
57
|
target_branch="${cfg_branch}"
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<!-- AIWS_MANAGED_BEGIN:claude:ws-push -->
|
|
2
|
+
# ws push
|
|
3
|
+
|
|
4
|
+
用中文输出(命令/路径/代码标识符保持原样不翻译)。
|
|
5
|
+
|
|
6
|
+
目标:安全 push 当前仓库;若仓库包含 submodules,则先 push submodules,再 push superproject(默认 fast-forward;不 force)。
|
|
7
|
+
|
|
8
|
+
强制约束:
|
|
9
|
+
- 不自动提交、不自动 `git add -A`
|
|
10
|
+
- 不使用 `--force` / `--force-with-lease`
|
|
11
|
+
- 若工作区不干净:停止并要求先 commit 或 stash
|
|
12
|
+
|
|
13
|
+
步骤(建议):
|
|
14
|
+
1) 输出上下文并检查工作区干净:
|
|
15
|
+
```bash
|
|
16
|
+
git branch --show-current
|
|
17
|
+
git status --porcelain
|
|
18
|
+
git status -sb
|
|
19
|
+
```
|
|
20
|
+
若 `git status --porcelain` 非空:停止。
|
|
21
|
+
|
|
22
|
+
2) 判断是否存在 submodules:
|
|
23
|
+
```bash
|
|
24
|
+
if [[ -f .gitmodules ]]; then
|
|
25
|
+
git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$' || true
|
|
26
|
+
fi
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
3) 若没有 submodules:正常 push(仍需用户确认远端/分支):
|
|
30
|
+
```bash
|
|
31
|
+
git remote -v
|
|
32
|
+
git push
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
4) 若有 submodules:先检查 `.gitmodules` 的 `submodule.<name>.branch` 是否齐全(缺失则停止并提示 `/ws-submodule-setup`):
|
|
36
|
+
```bash
|
|
37
|
+
missing=0
|
|
38
|
+
while read -r key sub_path; do
|
|
39
|
+
name="${key#submodule.}"; name="${name%.path}"
|
|
40
|
+
b="$(git config --file .gitmodules --get "submodule.${name}.branch" 2>/dev/null || true)"
|
|
41
|
+
if [[ -z "${b:-}" ]]; then
|
|
42
|
+
echo "error: missing .gitmodules submodule.${name}.branch (path=${sub_path})"
|
|
43
|
+
missing=1
|
|
44
|
+
fi
|
|
45
|
+
done < <(git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$' 2>/dev/null || true)
|
|
46
|
+
if [[ "$missing" -ne 0 ]]; then
|
|
47
|
+
echo "hint: run /ws-submodule-setup (and commit .gitmodules), then retry"
|
|
48
|
+
exit 2
|
|
49
|
+
fi
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
5) 逐个 push submodules(fast-forward only),再 push superproject:
|
|
53
|
+
```bash
|
|
54
|
+
base_branch="$(git branch --show-current)"
|
|
55
|
+
|
|
56
|
+
git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$' 2>/dev/null \
|
|
57
|
+
| while read -r key sub_path; do
|
|
58
|
+
name="${key#submodule.}"; name="${name%.path}"
|
|
59
|
+
echo "== submodule: ${sub_path} (${name}) =="
|
|
60
|
+
|
|
61
|
+
if [[ -n "$(git -C "${sub_path}" status --porcelain 2>/dev/null || true)" ]]; then
|
|
62
|
+
echo "error: submodule dirty: ${sub_path}"
|
|
63
|
+
exit 2
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
cfg_branch="$(git config --file .gitmodules --get "submodule.${name}.branch" 2>/dev/null || true)"
|
|
67
|
+
if [[ "${cfg_branch:-}" == "." ]]; then cfg_branch="$base_branch"; fi
|
|
68
|
+
target_branch="${cfg_branch}"
|
|
69
|
+
|
|
70
|
+
git -C "${sub_path}" fetch origin --prune
|
|
71
|
+
if ! git -C "${sub_path}" show-ref --verify --quiet "refs/remotes/origin/${target_branch}"; then
|
|
72
|
+
echo "error: missing origin/${target_branch} for ${sub_path}"
|
|
73
|
+
exit 2
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
if ! git -C "${sub_path}" merge-base --is-ancestor "origin/${target_branch}" HEAD; then
|
|
77
|
+
echo "error: non-fast-forward (submodule=${sub_path}, branch=${target_branch})"
|
|
78
|
+
exit 2
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
git -C "${sub_path}" push origin "HEAD:refs/heads/${target_branch}"
|
|
82
|
+
done
|
|
83
|
+
|
|
84
|
+
git remote -v
|
|
85
|
+
git push
|
|
86
|
+
```
|
|
87
|
+
<!-- AIWS_MANAGED_END:claude:ws-push -->
|
|
88
|
+
|
|
89
|
+
可在下方追加本项目对 Claude Code 的额外说明(托管块外内容会被保留)。
|
|
90
|
+
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<!-- AIWS_MANAGED_BEGIN:claude:ws-submodule-setup -->
|
|
2
|
+
# ws submodule setup
|
|
3
|
+
|
|
4
|
+
用中文输出(命令/路径/代码标识符保持原样不翻译)。
|
|
5
|
+
|
|
6
|
+
目标:为每个 submodule 写入 `.gitmodules` 的 `submodule.<name>.branch`(团队真值),让 `/ws-pull`、`/ws-finish` 能确定性地减少 detached 与人为差异;并使 `aiws validate` 的 submodule 分支门禁通过。
|
|
7
|
+
|
|
8
|
+
约束:
|
|
9
|
+
- 不自动提交、不自动 push(必须先输出 diff 并让用户确认)
|
|
10
|
+
- 不做破坏性命令
|
|
11
|
+
|
|
12
|
+
步骤(建议):
|
|
13
|
+
1) 确认工作区干净:
|
|
14
|
+
```bash
|
|
15
|
+
git status --porcelain
|
|
16
|
+
```
|
|
17
|
+
非空则停止。
|
|
18
|
+
|
|
19
|
+
2) 列出 submodules:
|
|
20
|
+
```bash
|
|
21
|
+
test -f .gitmodules || { echo "no .gitmodules"; exit 0; }
|
|
22
|
+
git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$'
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
3) 对每个 submodule 让用户选择目标分支(推荐具体分支名;可选 `.` 表示跟随 superproject 分支名):
|
|
26
|
+
```bash
|
|
27
|
+
while read -r key sub_path; do
|
|
28
|
+
name="${key#submodule.}"; name="${name%.path}"
|
|
29
|
+
echo "== submodule: ${name} path=${sub_path} =="
|
|
30
|
+
echo "[current] branch=$(git config --file .gitmodules --get submodule.${name}.branch || true)"
|
|
31
|
+
echo "[origin] HEAD=$(git -C \"${sub_path}\" symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null || true)"
|
|
32
|
+
done < <(git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$')
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
4) 写入分支配置:
|
|
36
|
+
```bash
|
|
37
|
+
git submodule set-branch --branch <branch-or-dot> <sub_path>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
5) 输出 diff 并让用户确认是否提交:
|
|
41
|
+
```bash
|
|
42
|
+
git diff -- .gitmodules
|
|
43
|
+
git status --porcelain
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
6) 用户确认后提交:
|
|
47
|
+
```bash
|
|
48
|
+
git add .gitmodules
|
|
49
|
+
git commit -m "chore(submodule): set tracking branches"
|
|
50
|
+
```
|
|
51
|
+
<!-- AIWS_MANAGED_END:claude:ws-submodule-setup -->
|
|
52
|
+
|
|
53
|
+
可在下方追加本项目对 Claude Code 的额外说明(托管块外内容会被保留)。
|
|
54
|
+
|
|
@@ -20,6 +20,7 @@ prompt = """
|
|
|
20
20
|
|
|
21
21
|
建议流程(按顺序):
|
|
22
22
|
1) 先确认真值文件存在并遵守:`AI_PROJECT.md` / `REQUIREMENTS.md` / `AI_WORKSPACE.md`。
|
|
23
|
+
2) 如果存在 `.gitmodules` 但缺少 `submodule.<name>.branch`,先运行 `ws:submodule-setup` 并提交 `.gitmodules`(否则 `aiws validate .` 会失败,且 submodule 工作流会产生人为差异)。
|
|
23
24
|
2) 发现 submodules:
|
|
24
25
|
- `git submodule status --recursive`
|
|
25
26
|
3) 逐个提交 submodules(按上一步顺序):
|
|
@@ -45,4 +46,3 @@ prompt = """
|
|
|
45
46
|
- `Merge:` `ws:finish`/`aiws change finish` 输出(into/from)
|
|
46
47
|
- `Evidence:` `.agentdocs/tmp/aiws-validate/*.json`(若使用 --stamp)
|
|
47
48
|
"""
|
|
48
|
-
|
|
@@ -18,6 +18,7 @@ prompt = """
|
|
|
18
18
|
- `git status --porcelain`
|
|
19
19
|
- `git branch --show-current`(或 `git rev-parse --abbrev-ref HEAD`)
|
|
20
20
|
4) 若工作区不干净:停止,并要求先 commit 或 stash(不要尝试自动处理)。
|
|
21
|
+
4.1) 若存在 `.gitmodules`:必须为每个 submodule 配置 `submodule.<name>.branch`(否则先运行 `ws:submodule-setup` 并提交 `.gitmodules`)。
|
|
21
22
|
5) (推荐)门禁校验并落盘证据:`aiws validate . --stamp`(未安装全局 aiws 时可用 `npx @aipper/aiws validate . --stamp`)。
|
|
22
23
|
6) 安全合并(默认 fast-forward):
|
|
23
24
|
- 在 `change/<change-id>` 分支上:`aiws change finish`(会尝试读 `changes/<change-id>/.ws-change.json` 的 `base_branch` 并切回目标分支)
|
|
@@ -27,11 +28,11 @@ prompt = """
|
|
|
27
28
|
- 发现 submodules:`git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$'`
|
|
28
29
|
- 对每个 `<sub_path>`:
|
|
29
30
|
- 读取 superproject 当前 gitlink:`git rev-parse "HEAD:<sub_path>"`
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
- push
|
|
34
|
-
9) 任一 submodule
|
|
31
|
+
- 目标分支:必须在 `.gitmodules` 配置 `submodule.<name>.branch`(若为 `.` 则用当前主仓库分支;避免 origin 多分支时误判)
|
|
32
|
+
- 用 pin 分支挂回(不改动现有 main/master 指针):`git -C "<sub_path>" checkout -B "aiws/pin/<target-branch>" <gitlink-sha>`
|
|
33
|
+
- 仅当 `<gitlink-sha>` 属于 `origin/<target-branch>` 历史时才允许 push;否则停止并人工处理分叉
|
|
34
|
+
- push(只允许 fast-forward):`git -C "<sub_path>" push origin "<gitlink-sha>:refs/heads/<target-branch>"`
|
|
35
|
+
9) 任一 submodule 不满足 fast-forward 条件时立即停止(不要继续 push 主仓库)。
|
|
35
36
|
10) submodules push 完成后,再 push 主仓库当前分支:
|
|
36
37
|
- `git branch --show-current`
|
|
37
38
|
- `git status -sb`
|
|
@@ -43,4 +43,5 @@ prompt = """
|
|
|
43
43
|
可选(方案 2,一次性设置 submodule 跟踪分支,会改 `.gitmodules`,需提交):
|
|
44
44
|
- `git submodule set-branch --branch main <sub_path>`
|
|
45
45
|
- `git add .gitmodules && git commit -m "chore(submodule): set tracking branch"`
|
|
46
|
+
推荐:优先使用 `ws:submodule-setup` 交互式对齐所有 submodules 的 branch,并提交 `.gitmodules`。
|
|
46
47
|
"""
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Command: ws:push
|
|
2
|
+
# Description: 推送(submodule 感知:先 submodules 后 superproject;fast-forward;不 force)
|
|
3
|
+
# Category: workspace
|
|
4
|
+
# Version: 1
|
|
5
|
+
|
|
6
|
+
description = "推送(submodule 感知:先 submodules 后 superproject;fast-forward;不 force)"
|
|
7
|
+
|
|
8
|
+
prompt = """
|
|
9
|
+
用中文输出(命令/路径/代码标识符保持原样不翻译)。
|
|
10
|
+
|
|
11
|
+
目标:安全 push 当前仓库;若仓库包含 submodules,则先 push submodules,再 push superproject(默认 fast-forward;不 force)。
|
|
12
|
+
|
|
13
|
+
约束:
|
|
14
|
+
- 不自动提交、不自动 `git add -A`
|
|
15
|
+
- 不使用 `--force` / `--force-with-lease`
|
|
16
|
+
- 若工作区不干净:停止并要求先 commit 或 stash
|
|
17
|
+
|
|
18
|
+
步骤(建议):
|
|
19
|
+
1) 输出上下文并检查工作区干净:
|
|
20
|
+
- `git branch --show-current`
|
|
21
|
+
- `git status --porcelain`
|
|
22
|
+
- `git status -sb`
|
|
23
|
+
- 非空则停止。
|
|
24
|
+
|
|
25
|
+
2) 判断是否存在 submodules:若存在 `.gitmodules`,输出 submodule 列表:
|
|
26
|
+
- `git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$'`
|
|
27
|
+
|
|
28
|
+
3) 若没有 submodules:正常 push(仍需用户确认远端/分支):
|
|
29
|
+
- `git remote -v`
|
|
30
|
+
- `git push`
|
|
31
|
+
|
|
32
|
+
4) 若有 submodules:先检查 `.gitmodules` 的 `submodule.<name>.branch` 是否齐全(缺失则停止并提示 `ws:submodule-setup`)。
|
|
33
|
+
|
|
34
|
+
5) 逐个 push submodules(fast-forward only),再 push superproject:
|
|
35
|
+
- `git -C "<sub_path>" fetch origin --prune`
|
|
36
|
+
- 若 `origin/<target_branch>` 不是 `HEAD` 的祖先:停止并提示先在 submodule 做 rebase/merge
|
|
37
|
+
- `git -C "<sub_path>" push origin "HEAD:refs/heads/<target_branch>"`
|
|
38
|
+
- 最后 `git push`
|
|
39
|
+
"""
|
|
40
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Command: ws:submodule-setup
|
|
2
|
+
# Description: 子模块分支对齐(写入 .gitmodules 的 submodule.<name>.branch)
|
|
3
|
+
# Category: workspace
|
|
4
|
+
# Version: 1
|
|
5
|
+
|
|
6
|
+
description = "子模块分支对齐(写入 .gitmodules 的 submodule.<name>.branch)"
|
|
7
|
+
|
|
8
|
+
prompt = """
|
|
9
|
+
用中文输出(命令/路径/代码标识符保持原样不翻译)。
|
|
10
|
+
|
|
11
|
+
目标:为每个 submodule 写入 `.gitmodules` 的 `submodule.<name>.branch`(团队真值),让 `ws:pull`、`ws:finish` 能确定性地减少 detached 与人为差异;并使 `aiws validate` 的 submodule 分支门禁通过。
|
|
12
|
+
|
|
13
|
+
约束:
|
|
14
|
+
- 不自动提交、不自动 push(必须先输出 diff 并让用户确认)
|
|
15
|
+
- 不做破坏性命令
|
|
16
|
+
|
|
17
|
+
步骤(建议):
|
|
18
|
+
1) 确认工作区干净:`git status --porcelain`(非空则停止)。
|
|
19
|
+
2) 列出 submodules:
|
|
20
|
+
- `test -f .gitmodules || { echo "no .gitmodules"; exit 0; }`
|
|
21
|
+
- `git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$'`
|
|
22
|
+
3) 对每个 submodule 让用户选择目标分支(推荐具体分支名;可选 `.` 表示跟随 superproject 分支名)。
|
|
23
|
+
4) 写入分支配置:
|
|
24
|
+
- `git submodule set-branch --branch <branch-or-dot> <sub_path>`
|
|
25
|
+
5) 输出 diff 并让用户确认是否提交:
|
|
26
|
+
- `git diff -- .gitmodules`
|
|
27
|
+
- `git status --porcelain`
|
|
28
|
+
6) 用户确认后提交:
|
|
29
|
+
- `git add .gitmodules`
|
|
30
|
+
- `git commit -m "chore(submodule): set tracking branches"`
|
|
31
|
+
"""
|
|
32
|
+
|
|
@@ -18,6 +18,7 @@ description: 交付:submodules+superproject 分步提交并安全合并回 bas
|
|
|
18
18
|
|
|
19
19
|
建议流程(按顺序):
|
|
20
20
|
1) 先运行 `/ws-preflight`。
|
|
21
|
+
2) 如果存在 `.gitmodules` 但缺少 `submodule.<name>.branch`,先运行 `/ws-submodule-setup` 并提交 `.gitmodules`(否则 `aiws validate .` 会失败,且 submodule 工作流会产生人为差异)。
|
|
21
22
|
2) 发现 submodules:
|
|
22
23
|
- `git submodule status --recursive`
|
|
23
24
|
3) 逐个提交 submodules(按上一步顺序):
|
|
@@ -12,23 +12,42 @@ description: 收尾:fast-forward 合并并把 submodule 并回目标分支后
|
|
|
12
12
|
前置(必须):
|
|
13
13
|
- 工作区干净:`git status --porcelain` 无输出(否则先 commit 或 stash)
|
|
14
14
|
- change 分支存在(`change/<change-id>`;也支持 `changes/`、`ws/`、`ws-change/`)
|
|
15
|
+
- 若存在 `.gitmodules`:必须为每个 submodule 配置 `submodule.<name>.branch`(否则先运行 `/ws-submodule-setup` 并提交 `.gitmodules`)
|
|
15
16
|
|
|
16
17
|
步骤(建议):
|
|
18
|
+
0) 若存在 `.gitmodules`,先检查 submodule branch 配置是否齐全(缺失则停止并提示 setup):
|
|
19
|
+
```bash
|
|
20
|
+
if [[ -f .gitmodules ]]; then
|
|
21
|
+
missing=0
|
|
22
|
+
while read -r key sub_path; do
|
|
23
|
+
name="${key#submodule.}"; name="${name%.path}"
|
|
24
|
+
b="$(git config --file .gitmodules --get "submodule.${name}.branch" 2>/dev/null || true)"
|
|
25
|
+
if [[ -z "${b:-}" ]]; then
|
|
26
|
+
echo "error: missing .gitmodules submodule.${name}.branch (path=${sub_path})"
|
|
27
|
+
missing=1
|
|
28
|
+
fi
|
|
29
|
+
done < <(git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$' 2>/dev/null || true)
|
|
30
|
+
if [[ "$missing" -ne 0 ]]; then
|
|
31
|
+
echo "hint: run /ws-submodule-setup (and commit .gitmodules), then retry"
|
|
32
|
+
exit 2
|
|
33
|
+
fi
|
|
34
|
+
fi
|
|
35
|
+
```
|
|
17
36
|
1) 先运行 `/ws-preflight`(确保真值文件齐全)。
|
|
18
37
|
2) (推荐)门禁校验并落盘证据:`aiws validate . --stamp`(未安装全局 aiws 时可用 `npx @aipper/aiws validate . --stamp`)。
|
|
19
38
|
3) 安全合并并切回目标分支:
|
|
20
39
|
- 若当前就在 `change/<change-id>` 分支上,可直接执行:`aiws change finish`
|
|
21
40
|
- 否则执行:`aiws change finish <change-id>`
|
|
22
41
|
4) 若提示无法 fast-forward:先在 change 分支(或对应 worktree)里 `git rebase <target-branch>`,再重试 `aiws change finish`。
|
|
23
|
-
5) 合并成功后,按顺序处理每个 submodule
|
|
42
|
+
5) 合并成功后,按顺序处理每个 submodule(减少 detached;再 push):
|
|
24
43
|
- 发现 submodules:`git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$'`
|
|
25
44
|
- 对每个 `<sub_path>`:
|
|
26
45
|
- 读取 superproject 当前 gitlink:`git rev-parse "HEAD:<sub_path>"`
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
- push
|
|
31
|
-
6) 任一 submodule
|
|
46
|
+
- 目标分支:必须在 `.gitmodules` 配置 `submodule.<name>.branch`(若为 `.` 则用当前主仓库分支;避免 origin 多分支时误判)
|
|
47
|
+
- 用 pin 分支挂回(不改动现有 main/master 指针):`git -C "<sub_path>" checkout -B "aiws/pin/<target-branch>" <gitlink-sha>`
|
|
48
|
+
- 仅当 `<gitlink-sha>` 属于 `origin/<target-branch>` 历史时才允许 push;否则停止并人工处理分叉
|
|
49
|
+
- push(只允许 fast-forward):`git -C "<sub_path>" push origin "<gitlink-sha>:refs/heads/<target-branch>"`
|
|
50
|
+
6) 任一 submodule 不满足 fast-forward 条件时立即停止(不要继续 push 主仓库)。
|
|
32
51
|
7) submodules 全部成功后,再 push 主仓库当前分支:
|
|
33
52
|
- `git branch --show-current`
|
|
34
53
|
- `git status -sb`
|
|
@@ -39,7 +39,7 @@ fi
|
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
4) (可选但推荐)把 submodule 从 detached HEAD 尽量“挂回分支”(不改动 gitlink commit):
|
|
42
|
-
为避免 origin 多分支时“猜错分支”,本步骤只在 `.gitmodules` 明确配置了 `submodule.<name>.branch` 时才执行;否则保持 detached
|
|
42
|
+
为避免 origin 多分支时“猜错分支”,本步骤只在 `.gitmodules` 明确配置了 `submodule.<name>.branch` 时才执行;否则保持 detached 并提示先运行 `/ws-submodule-setup` 对齐配置。
|
|
43
43
|
```bash
|
|
44
44
|
if [[ -f .gitmodules ]]; then
|
|
45
45
|
base_branch="$(git branch --show-current)"
|
|
@@ -54,7 +54,7 @@ if [[ -f .gitmodules ]]; then
|
|
|
54
54
|
cfg_branch="$(git config --file .gitmodules --get "submodule.${name}.branch" 2>/dev/null || true)"
|
|
55
55
|
if [[ "${cfg_branch:-}" == "." ]]; then cfg_branch="$base_branch"; fi
|
|
56
56
|
if [[ -z "${cfg_branch:-}" ]]; then
|
|
57
|
-
echo "[warn] ${sub_path}: missing .gitmodules submodule.${name}.branch; keep detached"
|
|
57
|
+
echo "[warn] ${sub_path}: missing .gitmodules submodule.${name}.branch; keep detached (run ws-submodule-setup)"
|
|
58
58
|
continue
|
|
59
59
|
fi
|
|
60
60
|
target_branch="${cfg_branch}"
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: 推送:submodule 感知(先 submodules 后 superproject;fast-forward;不 force)
|
|
3
|
+
---
|
|
4
|
+
<!-- AIWS_MANAGED_BEGIN:opencode:ws-push -->
|
|
5
|
+
# ws push
|
|
6
|
+
|
|
7
|
+
用中文输出(命令/路径/代码标识符保持原样不翻译)。
|
|
8
|
+
|
|
9
|
+
目标:安全 push 当前仓库;若仓库包含 submodules,则先 push submodules,再 push superproject(默认 fast-forward;不 force)。
|
|
10
|
+
|
|
11
|
+
强制约束:
|
|
12
|
+
- 不自动提交、不自动 `git add -A`
|
|
13
|
+
- 不使用 `--force` / `--force-with-lease`
|
|
14
|
+
- 若工作区不干净:停止并要求先 commit 或 stash
|
|
15
|
+
|
|
16
|
+
步骤(建议):
|
|
17
|
+
1) 输出上下文并检查工作区干净:
|
|
18
|
+
```bash
|
|
19
|
+
git branch --show-current
|
|
20
|
+
git status --porcelain
|
|
21
|
+
git status -sb
|
|
22
|
+
```
|
|
23
|
+
若 `git status --porcelain` 非空:停止。
|
|
24
|
+
|
|
25
|
+
2) 判断是否存在 submodules:
|
|
26
|
+
```bash
|
|
27
|
+
if [[ -f .gitmodules ]]; then
|
|
28
|
+
git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$' || true
|
|
29
|
+
fi
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
3) 若没有 submodules:正常 push(仍需用户确认远端/分支):
|
|
33
|
+
```bash
|
|
34
|
+
git remote -v
|
|
35
|
+
git push
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
4) 若有 submodules:先检查 `.gitmodules` 的 `submodule.<name>.branch` 是否齐全(缺失则停止并提示 `/ws-submodule-setup`):
|
|
39
|
+
```bash
|
|
40
|
+
missing=0
|
|
41
|
+
while read -r key sub_path; do
|
|
42
|
+
name="${key#submodule.}"; name="${name%.path}"
|
|
43
|
+
b="$(git config --file .gitmodules --get "submodule.${name}.branch" 2>/dev/null || true)"
|
|
44
|
+
if [[ -z "${b:-}" ]]; then
|
|
45
|
+
echo "error: missing .gitmodules submodule.${name}.branch (path=${sub_path})"
|
|
46
|
+
missing=1
|
|
47
|
+
fi
|
|
48
|
+
done < <(git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$' 2>/dev/null || true)
|
|
49
|
+
if [[ "$missing" -ne 0 ]]; then
|
|
50
|
+
echo "hint: run /ws-submodule-setup (and commit .gitmodules), then retry"
|
|
51
|
+
exit 2
|
|
52
|
+
fi
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
5) 逐个 push submodules(fast-forward only),再 push superproject:
|
|
56
|
+
```bash
|
|
57
|
+
base_branch="$(git branch --show-current)"
|
|
58
|
+
|
|
59
|
+
git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$' 2>/dev/null \
|
|
60
|
+
| while read -r key sub_path; do
|
|
61
|
+
name="${key#submodule.}"; name="${name%.path}"
|
|
62
|
+
echo "== submodule: ${sub_path} (${name}) =="
|
|
63
|
+
|
|
64
|
+
if [[ -n "$(git -C "${sub_path}" status --porcelain 2>/dev/null || true)" ]]; then
|
|
65
|
+
echo "error: submodule dirty: ${sub_path}"
|
|
66
|
+
exit 2
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
cfg_branch="$(git config --file .gitmodules --get "submodule.${name}.branch" 2>/dev/null || true)"
|
|
70
|
+
if [[ "${cfg_branch:-}" == "." ]]; then cfg_branch="$base_branch"; fi
|
|
71
|
+
target_branch="${cfg_branch}"
|
|
72
|
+
|
|
73
|
+
git -C "${sub_path}" fetch origin --prune
|
|
74
|
+
if ! git -C "${sub_path}" show-ref --verify --quiet "refs/remotes/origin/${target_branch}"; then
|
|
75
|
+
echo "error: missing origin/${target_branch} for ${sub_path}"
|
|
76
|
+
exit 2
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
if ! git -C "${sub_path}" merge-base --is-ancestor "origin/${target_branch}" HEAD; then
|
|
80
|
+
echo "error: non-fast-forward (submodule=${sub_path}, branch=${target_branch})"
|
|
81
|
+
exit 2
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
git -C "${sub_path}" push origin "HEAD:refs/heads/${target_branch}"
|
|
85
|
+
done
|
|
86
|
+
|
|
87
|
+
git remote -v
|
|
88
|
+
git push
|
|
89
|
+
```
|
|
90
|
+
<!-- AIWS_MANAGED_END:opencode:ws-push -->
|
|
91
|
+
|
|
92
|
+
可在下方追加本项目对 OpenCode 的额外说明(托管块外内容会被保留)。
|
|
93
|
+
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: 子模块分支对齐(写入 .gitmodules 的 submodule.<name>.branch)
|
|
3
|
+
---
|
|
4
|
+
<!-- AIWS_MANAGED_BEGIN:opencode:ws-submodule-setup -->
|
|
5
|
+
# ws submodule setup
|
|
6
|
+
|
|
7
|
+
用中文输出(命令/路径/代码标识符保持原样不翻译)。
|
|
8
|
+
|
|
9
|
+
目标:为每个 submodule 写入 `.gitmodules` 的 `submodule.<name>.branch`(团队真值),让 `/ws-pull`、`/ws-finish` 能确定性地减少 detached 与人为差异;并使 `aiws validate` 的 submodule 分支门禁通过。
|
|
10
|
+
|
|
11
|
+
约束:
|
|
12
|
+
- 不自动提交、不自动 push(必须先输出 diff 并让用户确认)
|
|
13
|
+
- 不做破坏性命令
|
|
14
|
+
|
|
15
|
+
步骤(建议):
|
|
16
|
+
1) 确认工作区干净:
|
|
17
|
+
```bash
|
|
18
|
+
git status --porcelain
|
|
19
|
+
```
|
|
20
|
+
非空则停止。
|
|
21
|
+
|
|
22
|
+
2) 列出 submodules:
|
|
23
|
+
```bash
|
|
24
|
+
test -f .gitmodules || { echo "no .gitmodules"; exit 0; }
|
|
25
|
+
git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$'
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
3) 对每个 submodule 让用户选择目标分支(推荐具体分支名;可选 `.` 表示跟随 superproject 分支名):
|
|
29
|
+
```bash
|
|
30
|
+
while read -r key sub_path; do
|
|
31
|
+
name="${key#submodule.}"; name="${name%.path}"
|
|
32
|
+
echo "== submodule: ${name} path=${sub_path} =="
|
|
33
|
+
echo "[current] branch=$(git config --file .gitmodules --get submodule.${name}.branch || true)"
|
|
34
|
+
echo "[origin] HEAD=$(git -C \"${sub_path}\" symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null || true)"
|
|
35
|
+
done < <(git config --file .gitmodules --get-regexp '^submodule\\..*\\.path$')
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
4) 写入分支配置:
|
|
39
|
+
```bash
|
|
40
|
+
git submodule set-branch --branch <branch-or-dot> <sub_path>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
5) 输出 diff 并让用户确认是否提交:
|
|
44
|
+
```bash
|
|
45
|
+
git diff -- .gitmodules
|
|
46
|
+
git status --porcelain
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
6) 用户确认后提交:
|
|
50
|
+
```bash
|
|
51
|
+
git add .gitmodules
|
|
52
|
+
git commit -m "chore(submodule): set tracking branches"
|
|
53
|
+
```
|
|
54
|
+
<!-- AIWS_MANAGED_END:opencode:ws-submodule-setup -->
|
|
55
|
+
|
|
56
|
+
可在下方追加本项目对 OpenCode 的额外说明(托管块外内容会被保留)。
|
|
57
|
+
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
- 启用本机门禁(推荐):`aiws hooks install .`(或手工:`git config core.hooksPath .githooks`;`git commit`/`git push` 会自动跑 `aiws validate .`)
|
|
11
11
|
- 提交前校验(强制门禁):`aiws validate .`(包含:漂移检测 + `ws_change_check` + `requirements_contract`)
|
|
12
12
|
- Codex(推荐):本仓库内置 repo skills:`.agents/skills/`(可显式 `$ws-dev`,也可隐式套用工作流)
|
|
13
|
-
- Codex skills(常用):`$ws-preflight` / `$ws-plan` / `$ws-plan-verify` / `$ws-dev` / `$ws-pull` / `$ws-review` / `$ws-commit` / `$aiws-init` / `$aiws-validate` / `$aiws-hooks-install` / `$aiws-change-new`
|
|
13
|
+
- Codex skills(常用):`$ws-preflight` / `$ws-submodule-setup` / `$ws-plan` / `$ws-plan-verify` / `$ws-dev` / `$ws-pull` / `$ws-push` / `$ws-review` / `$ws-commit` / `$aiws-init` / `$aiws-validate` / `$aiws-hooks-install` / `$aiws-change-new`
|
|
14
14
|
- Codex CLI(推荐,可选):安装全局 skills:`npx @aipper/aiws codex install-skills`(写入 `~/.codex/skills/` 或 `$CODEX_HOME/skills`)
|
|
15
15
|
- Codex CLI(遗留,可选):安装全局 prompts:`npx @aipper/aiws codex install-prompts`(写入 `~/.codex/prompts/` 或 `$CODEX_HOME/prompts`;prompts 已 deprecated)
|
|
16
16
|
- 不要把敏感信息写入 git:`secrets/test-accounts.json`、`.env*`、token、内网地址等
|
|
@@ -31,7 +31,9 @@
|
|
|
31
31
|
".claude/commands/ws-deliver.md",
|
|
32
32
|
".claude/commands/ws-analyze.md",
|
|
33
33
|
".claude/commands/ws-pull.md",
|
|
34
|
+
".claude/commands/ws-push.md",
|
|
34
35
|
".claude/commands/ws-finish.md",
|
|
36
|
+
".claude/commands/ws-submodule-setup.md",
|
|
35
37
|
".claude/commands/ws-review.md",
|
|
36
38
|
".claude/commands/ws-commit.md",
|
|
37
39
|
".claude/commands/ws-rule.md",
|
|
@@ -50,7 +52,9 @@
|
|
|
50
52
|
".opencode/command/ws-deliver.md",
|
|
51
53
|
".opencode/command/ws-analyze.md",
|
|
52
54
|
".opencode/command/ws-pull.md",
|
|
55
|
+
".opencode/command/ws-push.md",
|
|
53
56
|
".opencode/command/ws-finish.md",
|
|
57
|
+
".opencode/command/ws-submodule-setup.md",
|
|
54
58
|
".opencode/command/ws-review.md",
|
|
55
59
|
".opencode/command/ws-commit.md",
|
|
56
60
|
".opencode/command/ws-rule.md",
|
|
@@ -78,7 +82,9 @@
|
|
|
78
82
|
".iflow/commands/ws-analyze.toml",
|
|
79
83
|
".iflow/commands/ws-deliver.toml",
|
|
80
84
|
".iflow/commands/ws-pull.toml",
|
|
85
|
+
".iflow/commands/ws-push.toml",
|
|
81
86
|
".iflow/commands/ws-finish.toml",
|
|
87
|
+
".iflow/commands/ws-submodule-setup.toml",
|
|
82
88
|
".iflow/commands/ws-review.toml",
|
|
83
89
|
".iflow/commands/ws-commit.toml",
|
|
84
90
|
".iflow/commands/ws-rule.toml",
|
|
@@ -141,6 +147,8 @@
|
|
|
141
147
|
".agents/skills/ws-plan/SKILL.md",
|
|
142
148
|
".agents/skills/ws-plan-verify/SKILL.md",
|
|
143
149
|
".agents/skills/ws-pull/SKILL.md",
|
|
150
|
+
".agents/skills/ws-push/SKILL.md",
|
|
151
|
+
".agents/skills/ws-submodule-setup/SKILL.md",
|
|
144
152
|
".agents/skills/ws-preflight/SKILL.md",
|
|
145
153
|
".agents/skills/ws-req-change/SKILL.md",
|
|
146
154
|
".agents/skills/ws-req-contract-sync/SKILL.md",
|
|
@@ -168,7 +176,9 @@
|
|
|
168
176
|
".iflow/commands/ws-analyze.toml",
|
|
169
177
|
".iflow/commands/ws-deliver.toml",
|
|
170
178
|
".iflow/commands/ws-pull.toml",
|
|
179
|
+
".iflow/commands/ws-push.toml",
|
|
171
180
|
".iflow/commands/ws-finish.toml",
|
|
181
|
+
".iflow/commands/ws-submodule-setup.toml",
|
|
172
182
|
".iflow/commands/ws-review.toml",
|
|
173
183
|
".iflow/commands/ws-commit.toml",
|
|
174
184
|
".iflow/commands/ws-rule.toml",
|
|
@@ -201,7 +211,9 @@
|
|
|
201
211
|
".claude/commands/ws-deliver.md": ["claude:ws-deliver"],
|
|
202
212
|
".claude/commands/ws-analyze.md": ["claude:ws-analyze"],
|
|
203
213
|
".claude/commands/ws-pull.md": ["claude:ws-pull"],
|
|
214
|
+
".claude/commands/ws-push.md": ["claude:ws-push"],
|
|
204
215
|
".claude/commands/ws-finish.md": ["claude:ws-finish"],
|
|
216
|
+
".claude/commands/ws-submodule-setup.md": ["claude:ws-submodule-setup"],
|
|
205
217
|
".claude/commands/ws-review.md": ["claude:ws-review"],
|
|
206
218
|
".claude/commands/ws-commit.md": ["claude:ws-commit"],
|
|
207
219
|
".claude/commands/ws-rule.md": ["claude:ws-rule"],
|
|
@@ -220,7 +232,9 @@
|
|
|
220
232
|
".opencode/command/ws-deliver.md": ["opencode:ws-deliver"],
|
|
221
233
|
".opencode/command/ws-analyze.md": ["opencode:ws-analyze"],
|
|
222
234
|
".opencode/command/ws-pull.md": ["opencode:ws-pull"],
|
|
235
|
+
".opencode/command/ws-push.md": ["opencode:ws-push"],
|
|
223
236
|
".opencode/command/ws-finish.md": ["opencode:ws-finish"],
|
|
237
|
+
".opencode/command/ws-submodule-setup.md": ["opencode:ws-submodule-setup"],
|
|
224
238
|
".opencode/command/ws-review.md": ["opencode:ws-review"],
|
|
225
239
|
".opencode/command/ws-commit.md": ["opencode:ws-commit"],
|
|
226
240
|
".opencode/command/ws-rule.md": ["opencode:ws-rule"],
|