关于 aep-git-ref
aep-git-ref 是 AEP Agent 工作流的 Git 与 worktree 规范参考,供其他技能和并行开发流程使用。它集中说明集成分支解析、worktree 生命周期、提交、PR 与恢复约定。
主要功能
- 01自动解析集成分支
- 02管理 worktree 生命周期
- 03规定分支命名与提交模式
- 04说明推送及 PR 约定
- 05提供 Git 故障恢复步骤
适用场景
- 01为并行 Agent 创建隔离工作区
- 02统一功能分支的提交与合并方式
- 03处理 worktree 或提交丢失问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ memorysaver/ agentic-engineering-patterns --skill aep-git-ref安装后在 Claude Code 中输入/aep-git-ref确认已加载。
详细介绍
Git + 工作树参考(AEP)
/aep-launch、/aep-build 和 /aep-wrap 使用普通 git 仓库和 git worktree 实现 Agent 并行隔离 — 这些技能提到“提交”时,指的就是 git commit。本技能是 AEP git 约定的权威来源:所有其他技能都会通过引用这里来解析 $BASE、创建/移除工作树和发起 PR,而不会重复写入这些代码块。选择普通 git 的理由(Agent 训练数据、通用工具):docs/decisions/migrate-from-jj-to-git.md。
集成分支
每项 AEP git 操作都针对集成分支 — 功能工作树从该分支创建、变基到该分支、向其发起 PR、合并到该分支;控制平面提交(/aep-dispatch、/aep-design、/aep-wrap 归档)也会落在该分支上。在本技能以及 /aep-launch、/aep-build、/aep-wrap 和产品上下文技能中的 bash 代码块里,此分支均记作 $BASE。
AEP 会自动检测以下两种模式之一 — 常见情况无需配置:
| 模式 | 条件 | 集成分支($BASE) | 生产分支 |
|---|---|---|---|
| 单分支(默认) | 不存在 develop 分支 | main | main(同一分支) |
| 双分支 | 存在 develop 分支 | develop(暂存) | main(仅用于发布) |
只需创建 develop 分支,项目就能从单分支模式扩展为双分支模式 — 无需重新配置。在双分支模式下,AEP 绝不触碰生产分支(main):从集成分支发布到生产分支(develop → main)由用户负责,与部署一样,这本来就不属于 AEP 的范围。
解析 $BASE
每个涉及 git 操作的技能都会在首个 bash 代码块的开头解析集成分支:
# Resolve AEP integration branch ($BASE): override → auto-detect develop → main
BASE=$(git config --get aep.integration-branch 2>/dev/null || true)
if [ -z "$BASE" ]; then
if git show-ref --verify --quiet refs/heads/develop \
|| git show-ref --verify --quiet refs/remotes/origin/develop; then
BASE=develop
else
BASE=main
fi
fi
解析顺序:
- 显式覆盖 —
git config --get aep.integration-branch。这仅用于覆盖默认值,适用于非标准集成分支名称(例如staging、integration)。标准的main/develop情况不需要设置 — 系统会自动检测。/aep-onboard会报告检测到的模式,且仅在使用非标准名称时写入此配置项 (git config aep.integration-branch <name>;使用git config --unset aep.integration-branch取消设置)。 - 自动检测 — 如果本地或
origin上存在develop,则使用develop。 - 默认值 —
main(单分支模式)。
由于标准情况会自动检测(而非固定指定),项目可以无需重新配置,从单分支模式扩展为双分支模式:创建 develop 后,每项技能在下次运行时都会将 $BASE 解析为该分支。(如果你曾将 aep.integration-branch=main 固定为覆盖值,该设置会优先生效并阻止升级 — 因此设置过程不会固定默认值。)
git config --get aep.integration-branch 是仓库本地配置,通过共享的 .git/config 在所有工作树间通用,因此 $BASE 在主会话和任何 .feature-workspaces/<name> 工作树中解析结果一致。
工作树生命周期
创建
# Resolve $BASE first — see "Resolving $BASE" above
mkdir -p .feature-workspaces
git worktree add -b feat/<name> .feature-workspaces/<name> "$BASE"
- 路径始终位于
.feature-workspaces/<name>下(该目录已加入 git 忽略规则)。 - 分支始终为
feat/<name>— 对应 OpenSpec 变更名称或故事 ID。 - 基准始终为集成分支
$BASE。
工作树与主仓库共享 .git/objects,因此创建速度很快,且不会重复存储历史记录。只有工作树文件会在磁盘上重复一份。
检查
git worktree list # all worktrees, branches, paths
git -C .feature-workspaces/<name> status # status inside a specific worktree
git -C .feature-workspaces/<name> log --oneline "$BASE"..HEAD # commits unique to the feature branch
移除(/aep-wrap 第 6 步)
git worktree remove .feature-workspaces/<name>
git branch -d feat/<name>
如果 git branch -d 警告分支尚未完全合并(很可能是因为 PR 采用 squash 合并,导致提交 SHA 不同),请先通过 gh pr view <number> --json state 确认 PR 状态为 MERGED,然后使用 git branch -D feat/<name> 强制删除。
从损坏的工作区目录中恢复
如果 .feature-workspaces/<name>/ 被手动删除:
git worktree prune # forget the orphaned registration
git branch -D feat/<name> # delete the orphan branch (if needed)
如果 .git/worktrees/<name>/ 仍引用一个不存在的路径(例如,你移动了父目录):
git worktree repair .feature-workspaces/<name>
分支命名
| 分支 | 模式 | 创建方式 |
|---|---|---|
| 功能开发 | feat/<short-name> | /aep-launch(每个故事一个) |
| 迁移 / 杂项 | chore/<short-name> | 视情况手动创建 |
| 从 main 分出的热修复 | fix/<short-name> | 手动创建 |
| 迁移项目 | migration/<topic> | 手动创建 |
规则:
- 斜杠后使用 kebab-case。不要使用空格或下划线。
- 名称应简短(≤ 30 个字符)——它们会显示在标签、信号文件和 PR 标题中。
- 工作区完全移除后,可以复用已删除的分支名(
git worktree prune会清除悬空引用)。
每项任务一个提交模式(/aep-build 的第 4 阶段)
内容
tasks.md 列出 N 项任务。功能分支最终会有 N 个提交,每项任务一个,顺序一致。采用 Conventional Commits 格式。工作区 Agent 线性实现任务,并在每项任务完成后提交,因此提交数与任务数一致:
# Implement task 1
# ... edit files ...
git add -A
git commit -m "feat(auth): extract auth service"
# Implement task 2
# ... edit files ...
git add -A
git commit -m "feat(auth): add token refresh flow"
# ... etc.
每次提交后,将短 SHA 记录到 .dev-workflow/feature-verification.json 中对应任务条目的 commit_sha 字段。
采用这种模式的原因
- PR 的提交列表就像目录,与
tasks.md中的任务一一对应。 - 每个提交都是一个自包含单元,评估器(第 5 阶段)和审阅者(第 11 阶段)都可以单独执行
git show <sha>查看。 - 我们会在合并 PR 时使用 squash merge,因此每个提交的规范性只影响审阅时的可读性——集成分支的历史会自动保持整洁。
- 这样无需在开发过程中重写历史,而这往往是 Agent 最容易出错的环节。
出现问题时的处理方式
| 情况 | 操作 |
|---|---|
| 忘记在刚提交的任务中包含某个文件 | git add <file> && git commit --amend --no-edit(仅在下一项任务提交之前安全) |
| 过了几个提交后才发现之前的任务有问题 | 新增一个提交:fix(<scope>): correct <issue from task N>——历史保持只追加 |
| 审阅反馈或评估循环 FAIL | 新增后续提交:fix(<scope>): address review on <topic> |
需要基于新的 origin/$BASE 更新 | git fetch origin && git rebase origin/"$BASE" && git push --force-with-lease origin feat/<name> |
| 变基时发生冲突 | 在工作树中解决冲突,然后运行 git add <files> && git rebase --continue。如果冲突纠缠不清,运行 git rebase --abort,并通过信号文件告知协调器。 |
推送重写后的分支时,使用 --force-with-lease,不要直接使用 --force:自上次获取以来,如果其他人已经推送了内容,lease 变体会安全地失败。
发布与 PR 约定
推送功能分支
# First push (after Phase 9 cleanup):
git push -u origin feat/<name>
# Subsequent pushes (review fixes, rebases):
git push origin feat/<name>
# or after a rebase:
git push --force-with-lease origin feat/<name>
打开 PR — 务必显式设置 base
# $BASE is the integration branch — resolve it first (see "Integration Branch" above)
gh pr create --base "$BASE" --title "<title>" --body "<body>"
--base "$BASE" 标志是必需的:如果不设置,gh 会根据本地分支状态推断 base(一次 dispatch 提交可能会被视为最近的 base),导致 PR 合并到非集成分支,代码也就永远不会进入 $BASE。在双分支模式下,推断出的 base 可能是生产分支 main,而 AEP 绝不会将功能工作合并到该分支。
合并 PR
gh pr merge <number> --squash --delete-branch
我们始终使用 squash 合并。功能分支上针对各项任务的提交会合并为一条提交,进入集成分支($BASE),这样既能让日志保持易读,也能在 PR 的 “Commits” 选项卡中保留各项任务的审查记录。
控制平面提交(在集成分支上)
/aep-design、/aep-dispatch、/aep-envision、/aep-map、/aep-calibrate、/aep-validate、/aep-reflect 和 /aep-wrap 的归档步骤都会直接提交到集成分支($BASE)。操作模式完全相同:
# Resolve $BASE first — see "Resolving $BASE" above
git pull --ff-only origin "$BASE" # fail-fast if the integration branch has diverged
git add <specific-files> # never -A on the integration branch; be explicit
git commit -m "<conventional message>"
git push origin "$BASE"
这里有意使用 --ff-only——它会拒绝非快进拉取,这意味着并发推送会被及时发现,而不会被静默合并。如果有人先推送导致拉取失败,请先获取更新,再对你的工作进行变基,然后重试。
恢复
丢失了提交(提交到了错误的分支,或通过 amend 将其移除)
git reflog # find the orphaned commit's SHA
git cherry-pick <sha> # bring it onto the current branch
# or
git reset --hard <sha> # if you want to rewind to that point
丢失了整个分支(使用 -D 删除)
git reflog # the deleted branch's tip is in here
git branch <name> <sha> # recreate the branch at that tip
丢失了已移除的工作树目录中的工作
如果你在提交前运行了 rm -rf .feature-workspaces/<name>,工作就会丢失——git worktree 只跟踪已提交的历史。.dev-workflow/ 文件(信号、经验教训、进度)也会一并丢失,因为它们被 gitignore 排除了。下次请使用 git worktree remove,而不是 rm -rf;如果工作树中有未提交的更改,该命令会拒绝执行。
变基后 OpenSpec 文件丢失
如果 dispatch 提交中的 OpenSpec 文件在变基或合并期间消失:
git log --oneline -n 30 # find the dispatch commit SHA
git restore --source=<sha> -- openspec/
这会将 openspec/ 恢复为 dispatch 提交时的状态,不会更改其他内容。
磁盘空间预算
每个工作树大约会在磁盘上增加一份完整的工作树副本。所有工作树共享 .git/objects,因此不会重复存储提交历史。对于典型的 AEP 仓库(工作树约 100 MB,经过多年积累后 .git/objects 达数 GB),三个并发 Agent 会在共享的 .git/ 之外额外占用约 300 MB。
使用以下命令监控:
du -sh .feature-workspaces/ # working-tree footprint
du -sh .git/objects # shared history
如果 Agent 完成工作前磁盘空间不足,请优先暂停启动新的 /aep-launch,而不是强制移除正在使用的工作树。
速查表
| 你想要…… | 运行 |
|---|---|
| 创建功能工作树 | git worktree add -b feat/<n> .feature-workspaces/<n> "$BASE" |
| 列出所有工作树 | git worktree list |
| 查看功能分支上的提交 | git log --oneline "$BASE"..HEAD |
与最新的 $BASE 同步 | git fetch origin && git rebase origin/"$BASE" |
| 变基后推送 | git push --force-with-lease origin feat/<n> |
| 打开 PR | gh pr create --base "$BASE" |
| 合并 PR | gh pr merge <#> --squash --delete-branch |
| 合并后移除工作树 | git worktree remove .feature-workspaces/<n> && git branch -d feat/<n> |
| 恢复已删除的提交 | git reflog 然后运行 git cherry-pick <sha> |
| 恢复丢失的 openspec/ 文件 | git restore --source=<sha> -- openspec/ |