Merge pull request 'fix: [product] Git Workflow 多 Session 并发隔离改造 - Closes #124' (#125) from dev/issue-124-git-worktree-isolation into main
CI / test (push) Successful in 23s
CI / test (push) Successful in 23s
This commit was merged in pull request #125.
This commit is contained in:
@@ -67,16 +67,17 @@ export GITEA_USER=pzhang_dev_agent_01 # Dev-Agent 账号
|
|||||||
- `C:\Users\peterz\projects\document_analyzer\docs\PROJECT_CHARTER.md`
|
- `C:\Users\peterz\projects\document_analyzer\docs\PROJECT_CHARTER.md`
|
||||||
- `C:\Users\peterz\projects\document_analyzer\docs\GLOBAL_STATE.md`
|
- `C:\Users\peterz\projects\document_analyzer\docs\GLOBAL_STATE.md`
|
||||||
2. 确认环境变量已设置(GITEA_USER + ~/.gitea/config.yaml)
|
2. 确认环境变量已设置(GITEA_USER + ~/.gitea/config.yaml)
|
||||||
3. 用 `/loop 10m` 开启 10 分钟间隔的自动轮询
|
3. 确认当前在独立的 git worktree 中(启动脚本已自动切到 `~/.gitea/worktrees/<user>/<timestamp>/`),不与其他 agent 共享工作目录。工作区始终基于 origin/main,请勿 checkout main 分支
|
||||||
4. 轮询内容(多轮递进):
|
4. 用 `/loop 10m` 开启 10 分钟间隔的自动轮询
|
||||||
|
5. 轮询内容(多轮递进):
|
||||||
a. `--action list --labels product-code` — 先捡带 `product-code` 标签的 Issue
|
a. `--action list --labels product-code` — 先捡带 `product-code` 标签的 Issue
|
||||||
b. `--action list` 无过滤,筛选 title 带 `[product]` 前缀的无标签 Issue
|
b. `--action list` 无过滤,筛选 title 带 `[product]` 前缀的无标签 Issue
|
||||||
c. `--action blocked-check` — 检查 blocked Issue,若阻塞已解除则自动移除 blocked 标签
|
c. `--action blocked-check` — 检查 blocked Issue,若阻塞已解除则自动移除 blocked 标签
|
||||||
d. 都无则分析无标签、无标识的 Issue,判断是否在 Dev 域内
|
d. 都无则分析无标签、无标识的 Issue,判断是否在 Dev 域内
|
||||||
5. 有 Issue → 走完整闭环处理(分析 → 开发 → push → PR → CI → merge → 自行验证 → 关闭)
|
6. 有 Issue → 走完整闭环处理(分析 → 开发 → push → PR → CI → merge → 自行验证 → 关闭)
|
||||||
- 关闭 Issue 时自动解除被该 Issue 阻塞的其他 Issue(移除 blocked 标签)
|
- 关闭 Issue 时自动解除被该 Issue 阻塞的其他 Issue(移除 blocked 标签)
|
||||||
6. 无 Issue → 报告 "main healthy,无待处理 Issue",等待下次轮询
|
7. 无 Issue → 报告 "main healthy,无待处理 Issue",等待下次轮询
|
||||||
7. 同时保持对话开放,随时响应用户指令
|
8. 同时保持对话开放,随时响应用户指令
|
||||||
|
|
||||||
## 上下文管理
|
## 上下文管理
|
||||||
Context window 有限。当 session 持续较长时间时:
|
Context window 有限。当 session 持续较长时间时:
|
||||||
@@ -117,8 +118,8 @@ python scripts/agent_poller.py --action get --issue N
|
|||||||
### 3. 开发 / 修复
|
### 3. 开发 / 修复
|
||||||
|
|
||||||
```
|
```
|
||||||
1. git pull origin main
|
1. git fetch origin
|
||||||
2. git checkout -b dev/issue-N-<slug>
|
2. git checkout -b dev/issue-N-<slug> origin/main
|
||||||
3. 修改代码 + 更新 UT
|
3. 修改代码 + 更新 UT
|
||||||
4. python -m pytest -v
|
4. python -m pytest -v
|
||||||
5. git commit -m "fix: <描述> - Closes #N"
|
5. git commit -m "fix: <描述> - Closes #N"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ description: "document_analyzer QE-Agent: 自动化验收测试开发与质量
|
|||||||
|
|
||||||
1. 读取项目章程和全局状态:`docs/PROJECT_CHARTER.md` 和 `docs/GLOBAL_STATE.md`
|
1. 读取项目章程和全局状态:`docs/PROJECT_CHARTER.md` 和 `docs/GLOBAL_STATE.md`
|
||||||
2. 设好环境变量(见下方"环境要求")
|
2. 设好环境变量(见下方"环境要求")
|
||||||
3. 确认当前在独立的 git worktree 中(启动脚本已自动切到 `~/.gitea/worktrees/`),不与其他 agent 共享工作目录
|
3. 确认当前在独立的 git worktree 中(启动脚本已自动切到 `~/.gitea/worktrees/<user>/<timestamp>/`),不与其他 agent 共享工作目录。工作区始终基于 origin/main,请勿 checkout main 分支
|
||||||
4. 用 `/loop 10m` 开启 10 分钟间隔的自动轮询
|
4. 用 `/loop 10m` 开启 10 分钟间隔的自动轮询
|
||||||
4. 轮询内容(多轮递进):
|
4. 轮询内容(多轮递进):
|
||||||
a. `--action list --labels test-code` — 先捡带 `test-code` 标签的 Issue
|
a. `--action list --labels test-code` — 先捡带 `test-code` 标签的 Issue
|
||||||
@@ -112,22 +112,16 @@ python scripts/agent_poller.py --action comment --issue <N> --body "QE-Agent 已
|
|||||||
|
|
||||||
### Step 3: 实施测试
|
### Step 3: 实施测试
|
||||||
|
|
||||||
#### 3.1 确保代码最新
|
#### 3.1 确保代码最新并创建分支
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git checkout main
|
git fetch origin
|
||||||
git pull origin main
|
git checkout -b test/issue-<N> origin/main
|
||||||
```
|
|
||||||
|
|
||||||
#### 3.2 创建分支
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git checkout -b test/issue-<N>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
分支命名规则:`test/issue-<N>` 或 `test/issue-<N>-<简短描述>`
|
分支命名规则:`test/issue-<N>` 或 `test/issue-<N>-<简短描述>`
|
||||||
|
|
||||||
#### 3.3 编写测试代码
|
#### 3.2 编写测试代码
|
||||||
|
|
||||||
测试代码在 `tests/acceptance/` 目录下。现有结构:
|
测试代码在 `tests/acceptance/` 目录下。现有结构:
|
||||||
|
|
||||||
@@ -149,7 +143,7 @@ tests/acceptance/
|
|||||||
- Layer B 覆盖率测试不需要 LLM API
|
- Layer B 覆盖率测试不需要 LLM API
|
||||||
- Layer C QE 审计需要 `deepseek-v4-flash` API
|
- Layer C QE 审计需要 `deepseek-v4-flash` API
|
||||||
|
|
||||||
#### 3.4 本地验证
|
#### 3.3 本地验证
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 跑全部验收测试(需要 LLM API)
|
# 跑全部验收测试(需要 LLM API)
|
||||||
|
|||||||
@@ -16,13 +16,21 @@
|
|||||||
- Agent 身份通过各自环境变量设置(Dev: `pzhang_dev_agent_01`,QE: `pzhang_qe_agent_01`)
|
- Agent 身份通过各自环境变量设置(Dev: `pzhang_dev_agent_01`,QE: `pzhang_qe_agent_01`)
|
||||||
- **所有 Gitea API 操作必须通过 `python scripts/agent_poller.py`**,禁止直接 curl 或硬编码 token
|
- **所有 Gitea API 操作必须通过 `python scripts/agent_poller.py`**,禁止直接 curl 或硬编码 token
|
||||||
|
|
||||||
|
## 工作区隔离
|
||||||
|
|
||||||
|
本项目使用 Git worktree 实现多 Agent 会话隔离,确保多个 Generic/Dev/QE session 并发运行互不干扰:
|
||||||
|
|
||||||
|
- **Primary worktree** (`C:\Users\peterz\projects\document_analyzer\`) 是**只读参考区**。仅用于代码阅读、git log 查询、文档查阅、启动脚本。**不在此目录做任何开发提交**。
|
||||||
|
- **Generic session 开发**:使用 `bash scripts/start_generic.sh` 启动,自动在 `~/.gitea/worktrees/pzhangzywl/<timestamp>/` 创建隔离工作区。
|
||||||
|
- **Agent sessions**:由 `start_dev_agent.sh` / `start_qe_agent.sh` 自动在 `~/.gitea/worktrees/<user>/<timestamp>/` 创建隔离工作区。
|
||||||
|
- 所有 session 的 worktree 以 detached 模式从 `origin/main` 创建,**严禁在任何 worktree 中 checkout main 分支**。
|
||||||
|
- Feature branch 直接从 `origin/main` 创建:`git fetch origin && git checkout -b <branch> origin/main`
|
||||||
|
|
||||||
## 代码同步
|
## 代码同步
|
||||||
|
|
||||||
Dev-Agent 和 QE-Agent 持续向 main 提交代码,本地可能落后。Session 启动时必须同步:
|
- Primary worktree:`git fetch origin` 即可(只读,不 pull)。
|
||||||
|
- 隔离 worktree:启动脚本自动从最新 `origin/main` 创建,始终是最新代码。
|
||||||
- **启动时**:自动执行 `git pull origin main`,确保本地是最新代码
|
- Session 运行中需要同步时:`git fetch origin`,新分支从最新 `origin/main` 创建。
|
||||||
- **运行中**:定期 `git fetch origin` 检查 `HEAD..origin/main`,有新提交则 pull
|
|
||||||
- **有冲突时**:暂停并报告,不自动解决(人工介入)
|
|
||||||
|
|
||||||
## 上下文管理
|
## 上下文管理
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -65,7 +65,7 @@ export GITEA_USER=pzhang_dev_agent_01 # Dev-Agent 账号
|
|||||||
|
|
||||||
1. 读取项目章程和全局状态:`docs/PROJECT_CHARTER.md` 和 `docs/GLOBAL_STATE.md`
|
1. 读取项目章程和全局状态:`docs/PROJECT_CHARTER.md` 和 `docs/GLOBAL_STATE.md`
|
||||||
2. 确认环境变量已设置(GITEA_USER + ~/.gitea/config.yaml)
|
2. 确认环境变量已设置(GITEA_USER + ~/.gitea/config.yaml)
|
||||||
3. 确认当前在独立的 git worktree 中(启动脚本已自动切到 `~/.gitea/worktrees/`),不与其他 agent 共享工作目录
|
3. 确认当前在独立的 git worktree 中(启动脚本已自动切到 `~/.gitea/worktrees/<user>/<timestamp>/`),不与其他 agent 共享工作目录。工作区始终基于 origin/main,请勿 checkout main 分支
|
||||||
4. 用 `/loop 10m` 开启 10 分钟间隔的自动轮询
|
4. 用 `/loop 10m` 开启 10 分钟间隔的自动轮询
|
||||||
4. 轮询内容(多轮递进):
|
4. 轮询内容(多轮递进):
|
||||||
a. `--action list --labels product-code` — 先捡带 `product-code` 标签的 Issue
|
a. `--action list --labels product-code` — 先捡带 `product-code` 标签的 Issue
|
||||||
@@ -156,8 +156,8 @@ python scripts/agent_poller.py --action get --issue N
|
|||||||
|
|
||||||
```
|
```
|
||||||
1. [判定] 是代码级修复还是质量级修复?
|
1. [判定] 是代码级修复还是质量级修复?
|
||||||
2. git pull origin main
|
2. git fetch origin
|
||||||
3. git checkout -b dev/issue-N-<slug>
|
3. git checkout -b dev/issue-N-<slug> origin/main
|
||||||
4. 修改功能代码 + 更新/补充 UT 和接口集成测试
|
4. 修改功能代码 + 更新/补充 UT 和接口集成测试
|
||||||
5. python -m pytest -v # 本地全量 UT/集成测试
|
5. python -m pytest -v # 本地全量 UT/集成测试
|
||||||
6. [仅质量级修复] python scripts/run_pipeline.py --input "input/<文档>.docx"
|
6. [仅质量级修复] python scripts/run_pipeline.py --input "input/<文档>.docx"
|
||||||
|
|||||||
+6
-12
@@ -15,7 +15,7 @@ description: QE Agent — 自动化验收测试开发与质量门禁。轮询 Gi
|
|||||||
|
|
||||||
1. 读取项目章程和全局状态:`docs/PROJECT_CHARTER.md` 和 `docs/GLOBAL_STATE.md`
|
1. 读取项目章程和全局状态:`docs/PROJECT_CHARTER.md` 和 `docs/GLOBAL_STATE.md`
|
||||||
2. 设好环境变量(见下方"环境要求")
|
2. 设好环境变量(见下方"环境要求")
|
||||||
3. 确认当前在独立的 git worktree 中(启动脚本已自动切到 `~/.gitea/worktrees/`),不与其他 agent 共享工作目录
|
3. 确认当前在独立的 git worktree 中(启动脚本已自动切到 `~/.gitea/worktrees/<user>/<timestamp>/`),不与其他 agent 共享工作目录。工作区始终基于 origin/main,请勿 checkout main 分支
|
||||||
4. 用 `/loop 10m` 开启 10 分钟间隔的自动轮询
|
4. 用 `/loop 10m` 开启 10 分钟间隔的自动轮询
|
||||||
4. 轮询内容(多轮递进):
|
4. 轮询内容(多轮递进):
|
||||||
a. `--action list --labels test-code` — 先捡带 `test-code` 标签的 Issue
|
a. `--action list --labels test-code` — 先捡带 `test-code` 标签的 Issue
|
||||||
@@ -111,22 +111,16 @@ python scripts/agent_poller.py --action comment --issue <N> --body "QE-Agent 已
|
|||||||
|
|
||||||
### Step 3: 实施测试
|
### Step 3: 实施测试
|
||||||
|
|
||||||
#### 3.1 确保代码最新
|
#### 3.1 确保代码最新并创建分支
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git checkout main
|
git fetch origin
|
||||||
git pull origin main
|
git checkout -b test/issue-<N> origin/main
|
||||||
```
|
|
||||||
|
|
||||||
#### 3.2 创建分支
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git checkout -b test/issue-<N>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
分支命名规则:`test/issue-<N>` 或 `test/issue-<N>-<简短描述>`
|
分支命名规则:`test/issue-<N>` 或 `test/issue-<N>-<简短描述>`
|
||||||
|
|
||||||
#### 3.3 编写测试代码
|
#### 3.2 编写测试代码
|
||||||
|
|
||||||
测试代码在 `tests/acceptance/` 目录下。现有结构:
|
测试代码在 `tests/acceptance/` 目录下。现有结构:
|
||||||
|
|
||||||
@@ -148,7 +142,7 @@ tests/acceptance/
|
|||||||
- Layer B 覆盖率测试不需要 LLM API
|
- Layer B 覆盖率测试不需要 LLM API
|
||||||
- Layer C QE 审计需要 `deepseek-v4-flash` API
|
- Layer C QE 审计需要 `deepseek-v4-flash` API
|
||||||
|
|
||||||
#### 3.4 本地验证
|
#### 3.3 本地验证
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 跑全部验收测试(需要 LLM API)
|
# 跑全部验收测试(需要 LLM API)
|
||||||
|
|||||||
+18
-19
@@ -21,37 +21,36 @@ fi
|
|||||||
|
|
||||||
# ── Worktree isolation ─────────────────────────────────────────────────────────
|
# ── Worktree isolation ─────────────────────────────────────────────────────────
|
||||||
GITEA_WORKTREE_DIR="${GITEA_WORKTREE_DIR:-$HOME/.gitea/worktrees}"
|
GITEA_WORKTREE_DIR="${GITEA_WORKTREE_DIR:-$HOME/.gitea/worktrees}"
|
||||||
|
_WORKTREE_PATH=""
|
||||||
|
|
||||||
setup_worktree() {
|
setup_worktree() {
|
||||||
local user="$1"
|
local user="$1"
|
||||||
local worktree="$GITEA_WORKTREE_DIR/$user"
|
local ts
|
||||||
|
ts="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
local worktree="$GITEA_WORKTREE_DIR/$user/$ts"
|
||||||
|
|
||||||
# Already inside a worktree we created — reuse it.
|
# Ensure origin/main is current so worktree starts from latest
|
||||||
if [ -f "$worktree/.gitea-worktree" ]; then
|
git -C "$_MAIN_REPO_DIR" fetch origin main 2>/dev/null || true
|
||||||
echo "Using existing worktree: $worktree"
|
|
||||||
PROJECT_DIR="$worktree"
|
|
||||||
cd "$PROJECT_DIR"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
local branch="agent/${user}/$(date +%Y%m%d-%H%M%S)"
|
echo "Creating worktree: $worktree (detached from origin/main)"
|
||||||
echo "Creating worktree: $worktree (branch: $branch)"
|
mkdir -p "$(dirname "$worktree")"
|
||||||
mkdir -p "$GITEA_WORKTREE_DIR"
|
git -C "$_MAIN_REPO_DIR" worktree add --detach "$worktree" origin/main
|
||||||
git -C "$_MAIN_REPO_DIR" worktree add -b "$branch" "$worktree" origin/main
|
|
||||||
touch "$worktree/.gitea-worktree"
|
touch "$worktree/.gitea-worktree"
|
||||||
|
|
||||||
PROJECT_DIR="$worktree"
|
PROJECT_DIR="$worktree"
|
||||||
|
_WORKTREE_PATH="$worktree"
|
||||||
cd "$PROJECT_DIR"
|
cd "$PROJECT_DIR"
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup_worktree() {
|
cleanup_worktree() {
|
||||||
local user="$1"
|
local worktree="${_WORKTREE_PATH:-}"
|
||||||
local worktree="$GITEA_WORKTREE_DIR/$user"
|
if [ -z "$worktree" ] || [ ! -f "$worktree/.gitea-worktree" ]; then
|
||||||
if [ -d "$worktree" ]; then
|
echo "No worktree to clean up (not created by this session)."
|
||||||
rm -f "$worktree/.gitea-worktree"
|
return 0
|
||||||
echo "Cleaning up worktree: $worktree"
|
|
||||||
git -C "$_MAIN_REPO_DIR" worktree remove "$worktree" 2>/dev/null || true
|
|
||||||
rm -rf "$worktree" 2>/dev/null || true
|
|
||||||
fi
|
fi
|
||||||
|
rm -f "$worktree/.gitea-worktree"
|
||||||
|
echo "Cleaning up worktree: $worktree"
|
||||||
|
git -C "$_MAIN_REPO_DIR" worktree remove --force "$worktree" 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Validate required environment ──────────────────────────────────────────────
|
# ── Validate required environment ──────────────────────────────────────────────
|
||||||
|
|||||||
@@ -19,15 +19,13 @@ source "$SCRIPT_DIR/_common.sh"
|
|||||||
setup_worktree "$GITEA_USER"
|
setup_worktree "$GITEA_USER"
|
||||||
|
|
||||||
# Cleanup worktree on exit (optional, comment out to keep for debugging)
|
# Cleanup worktree on exit (optional, comment out to keep for debugging)
|
||||||
trap 'cleanup_worktree "$GITEA_USER"' EXIT
|
trap 'cleanup_worktree' EXIT
|
||||||
|
|
||||||
banner "Dev"
|
banner "Dev"
|
||||||
require_token
|
require_token
|
||||||
|
|
||||||
AGENT_CONF="$_MAIN_REPO_DIR/.claude/agents/dev-agent.md"
|
|
||||||
launch_agent \
|
launch_agent \
|
||||||
"dev-agent" \
|
"dev-agent" \
|
||||||
"$AGENT_CONF" \
|
"$PROJECT_DIR/.claude/agents/dev-agent.md" \
|
||||||
"Dev-Agent" \
|
"Dev-Agent" \
|
||||||
"执行一次 Issue 巡检(单次任务,不要用 /loop):
|
"执行一次 Issue 巡检(单次任务,不要用 /loop):
|
||||||
1. python scripts/agent_poller.py --action list 列出所有打开的 Issue
|
1. python scripts/agent_poller.py --action list 列出所有打开的 Issue
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Generic session 启动脚本 — 为人类用户提供 worktree 隔离
|
||||||
|
# 用法: bash scripts/start_generic.sh
|
||||||
|
# GITEA_USER 默认 pzhangzywl(人类用户),可通过环境变量覆盖
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
export GITEA_USER="${GITEA_USER:-pzhangzywl}"
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
source "$SCRIPT_DIR/_common.sh"
|
||||||
|
|
||||||
|
setup_worktree "$GITEA_USER"
|
||||||
|
trap 'cleanup_worktree' EXIT
|
||||||
|
|
||||||
|
banner "Generic"
|
||||||
|
require_token
|
||||||
|
|
||||||
|
echo "工作目录: $PROJECT_DIR"
|
||||||
|
echo ""
|
||||||
|
cd "$PROJECT_DIR"
|
||||||
|
claude
|
||||||
@@ -19,15 +19,13 @@ source "$SCRIPT_DIR/_common.sh"
|
|||||||
setup_worktree "$GITEA_USER"
|
setup_worktree "$GITEA_USER"
|
||||||
|
|
||||||
# Cleanup worktree on exit (optional, comment out to keep for debugging)
|
# Cleanup worktree on exit (optional, comment out to keep for debugging)
|
||||||
trap 'cleanup_worktree "$GITEA_USER"' EXIT
|
trap 'cleanup_worktree' EXIT
|
||||||
|
|
||||||
banner "QE"
|
banner "QE"
|
||||||
require_token
|
require_token
|
||||||
|
|
||||||
AGENT_CONF="$_MAIN_REPO_DIR/.claude/agents/qe-agent.md"
|
|
||||||
launch_agent \
|
launch_agent \
|
||||||
"qe-agent" \
|
"qe-agent" \
|
||||||
"$AGENT_CONF" \
|
"$PROJECT_DIR/.claude/agents/qe-agent.md" \
|
||||||
"QE-Agent" \
|
"QE-Agent" \
|
||||||
"执行一次 Issue 巡检(单次任务,不要用 /loop):
|
"执行一次 Issue 巡检(单次任务,不要用 /loop):
|
||||||
1. python scripts/agent_poller.py --action list --labels test-code 检查 test-code Issue
|
1. python scripts/agent_poller.py --action list --labels test-code 检查 test-code Issue
|
||||||
|
|||||||
Reference in New Issue
Block a user