feat(分支基準): 參考與來源分支一律取遠端 origin,動作前先 fetch

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-25 11:10:55 +08:00
co-authored by Claude Opus 5
parent 082104c550
commit 543fd8c695
5 changed files with 35 additions and 15 deletions
+25 -5
View File
@@ -2,6 +2,24 @@
分析要讀對分支的程式碼,實作要寫進對的分支。兩件事都不能從「目前 checkout 的分支」推定使用者的意圖。 分析要讀對分支的程式碼,實作要寫進對的分支。兩件事都不能從「目前 checkout 的分支」推定使用者的意圖。
## 總則:一律以遠端為準,不吃本地分支
SDLC 各階段引用的參考分支與來源分支,**一律指遠端的 `origin/{分支}`**。本地分支不可作為基準。
理由:本地分支可能落後遠端、可能有沒推上去的 commit、也可能是別的工作留下的狀態。以本地為基準,分析會對著過時的程式碼做,實作會從錯誤的起點長出來,而且錯了不會有任何徵兆。
| 項目 | 規則 |
| --- | --- |
| 動作之前 | 先 `git fetch --prune origin`。**沒 fetch 就用 `origin/{分支}` 等於用快取**,遠端追蹤參照可能已經過時,連分支被刪掉都看不出來 |
| 列分支 | `git branch -r`,不看 `git branch` |
| 基準與比對 | 一律寫 `origin/{分支}`,例如 `git rev-list --count origin/master..origin/develop` |
| 建立 worktree | 從 `origin/{來源分支}` 建,不從本地同名分支建 |
| 判定預設分支 | `refs/remotes/origin/HEAD`(見〔判定遠端預設分支〕) |
**本地與遠端不一致時一律停下回報**,不自行 `pull`、不自行 `reset`、不自行切換。要不要同步是使用者的決定。
`origin` 以外的遠端名稱(例如 `upstream`):先問使用者以哪個遠端為準,不臆測。
## 先確認,再動工 ## 先確認,再動工
| 階段 | 要確認的分支 | 確認時機 | | 階段 | 要確認的分支 | 確認時機 |
@@ -11,7 +29,7 @@
確認方式: 確認方式:
1. 先把事實攤開:目前分支、工作區是否乾淨、遠端有哪些分支(`git branch -r`)、下節判定出的遠端預設分支。 1. 先 `git fetch --prune origin`,再把事實攤開:目前分支、工作區是否乾淨、遠端有哪些分支(`git branch -r`,不看本地)、下節判定出的遠端預設分支。
2. 依 `jsc-ask:ask` 的決策樹詢問,每個選項都要標明影響範圍。分析錯分支會產出對不上程式碼的工作包;目標分支錯了則 PR 會開到錯的地方。 2. 依 `jsc-ask:ask` 的決策樹詢問,每個選項都要標明影響範圍。分析錯分支會產出對不上程式碼的工作包;目標分支錯了則 PR 會開到錯的地方。
3. 把確認結果寫進產出(分析頁的來源分支欄、PR 的目標分支),後續步驟一律沿用同一個答案,不再自行改判。 3. 把確認結果寫進產出(分析頁的來源分支欄、PR 的目標分支),後續步驟一律沿用同一個答案,不再自行改判。
4. 使用者沒回答就**不預設** `develop`/`master`;預設值只在使用者明確同意後才成立。 4. 使用者沒回答就**不預設** `develop`/`master`;預設值只在使用者明確同意後才成立。
@@ -28,18 +46,20 @@
`analyze` 是 logic-only 階段: `analyze` 是 logic-only 階段:
- **工作目錄的 HEAD 必須與 `origin/{來源分支}` 指向同一個 commit**。落後、超前或分歧都代表讀到的不是遠端現況——停下來回報差距(`git rev-list --left-right --count origin/{來源分支}...HEAD`),請使用者自己處理。
- 需要換分支才能讀到正確現況時,**停下來請使用者自己切換**。 - 需要換分支才能讀到正確現況時,**停下來請使用者自己切換**。
- 不代為 `switch`、不 `stash`、不動工作區、不建分支。 - 不代為 `switch`、不 `stash`、不動工作區、不建分支。
## 實作階段的分支選擇 ## 實作階段的分支選擇
- 判斷同名與否,兩邊都用遠端的分支名(`origin/{來源分支}` 與 `origin/{目標分支}`)。
- **只有來源分支與目標分支同名時才開新的工作分支**:同名就不可在該分支上直接 commit,改從已更新到最新的目標分支建立新工作分支,後續操作都以新分支為準。不同名就在目前分支處理。 - **只有來源分支與目標分支同名時才開新的工作分支**:同名就不可在該分支上直接 commit,改從已更新到最新的目標分支建立新工作分支,後續操作都以新分支為準。不同名就在目前分支處理。
- 新分支名稱要可讀且不覆蓋既有分支;本地或遠端已存在同名分支時,換一個時間戳或短 hash。 - 新分支名稱要可讀且不覆蓋既有分支;本地或遠端已存在同名分支時,換一個時間戳或短 hash。
- 切換或建立分支屬不可忽略的狀態變更,要在輸出中講清楚原因與結果分支名稱。 - 切換或建立分支屬不可忽略的狀態變更,要在輸出中講清楚原因與結果分支名稱。
## 實作一律在 worktree 內進行 ## 實作一律在 worktree 內進行
`implement` 動任何程式碼之前,先從**分析頁記錄的來源分支**建立 git worktree。所有修改都在 worktree 內,主工作目錄的分支與工作區完全不動。 `implement` 動任何程式碼之前,先 `git fetch --prune origin`,再從**分析頁記錄的來源分支的遠端版本**(`origin/{來源分支}`)建立 git worktree。所有修改都在 worktree 內,主工作目錄的分支與工作區完全不動。
### 路徑 ### 路徑
@@ -57,8 +77,8 @@
| 選項 | 指令 | 影響 | | 選項 | 指令 | 影響 |
| --- | --- | --- | | --- | --- | --- |
| 以來源分支為基準開新工作分支 | `git worktree add -b {工作分支} {路徑} {來源分支}` | commit 落在新分支,來源分支不動 | | 以來源分支為基準開新工作分支 | `git worktree add -b {工作分支} {路徑} "origin/{來源分支}"` | commit 落在新分支,來源分支不動 |
| 直接簽出來源分支 | `git worktree add {路徑} {來源分支}` | commit 直接進來源分支;同一分支不能同時簽出於兩處 | | 直接簽出來源分支 | `git worktree add --track -b {來源分支} {路徑} "origin/{來源分支}"` | 建立追蹤遠端的本地分支再簽出;本地已存在同名分支時指令會失敗,此時先確認它與遠端一致才可改用 `git worktree add {路徑} {來源分支}`,不一致就停下回報 |
**不得自行預設**,也不得跳過詢問。 **不得自行預設**,也不得跳過詢問。
@@ -68,7 +88,7 @@
- 找不到該存取庫的本地 clone → **停下來問使用者路徑**,不自行 clone、不臆測位置。 - 找不到該存取庫的本地 clone → **停下來問使用者路徑**,不自行 clone、不臆測位置。
- 目標路徑已存在 → 不覆蓋。先確認它是不是同一份工作的 worktree(`git worktree list`),是就沿用,不是就回報並停止。 - 目標路徑已存在 → 不覆蓋。先確認它是不是同一份工作的 worktree(`git worktree list`),是就沿用,不是就回報並停止。
- 把 `.worktree/` 加進該存取庫的 `.git/info/exclude`(不動使用者的 `.gitignore`,那是專案共用檔)。 - 把 `.worktree/` 加進該存取庫的 `.git/info/exclude`(不動使用者的 `.gitignore`,那是專案共用檔)。
- 建立後在輸出中明確列出:worktree 路徑、簽出的分支、來源分支。 - 建立後在輸出中明確列出:worktree 路徑、簽出的分支、來源分支,以及 `origin/{來源分支}` 當下的 commit sha——那是這次實作的起點,要能事後追。
### 移除時機 ### 移除時機
+4 -4
View File
@@ -19,14 +19,14 @@ All wiki reads and writes go through `jsc-gitea:wiki`.
3. **Never claim a capability tag you have not verified with that script**, and never substitute your own judgement for its verdict. Non-zero exit = blocked: relay the script's message verbatim, stop the skill, do nothing else this turn. Do not run `unlock` to get past the gate; only the user may decide that. 3. **Never claim a capability tag you have not verified with that script**, and never substitute your own judgement for its verdict. Non-zero exit = blocked: relay the script's message verbatim, stop the skill, do nothing else this turn. Do not run `unlock` to get past the gate; only the user may decide that.
4. Exit 0 means the stage is locked. From now until the next stage's gate runs, the sdlc-gate hook blocks every prompt whose model stops satisfying the tags. 4. Exit 0 means the stage is locked. From now until the next stage's gate runs, the sdlc-gate hook blocks every prompt whose model stops satisfying the tags.
2. **Confirm the source branch** — the branch whose code counts as the current state: 2. **Confirm the source branch** — the branch whose code counts as the current state:
1. Report the working directory's current branch, plus the remote branches available (`git branch -r`) and whether the working tree is clean. 1. Run `git fetch --prune origin` first — without it, every `origin/...` reference is stale cache. Then report the working directory's current branch, the **remote** branches available (`git branch -r`; never `git branch`) and whether the working tree is clean.
2. Ask per `jsc-ask:ask` rules which branch the analysis reads from; state the impact scope on every option (analysing the wrong branch produces work packages for code that does not exist). 2. Ask per `jsc-ask:ask` rules which branch the analysis reads from; state the impact scope on every option (analysing the wrong branch produces work packages for code that does not exist).
3. When the chosen branch is not the current one, **stop and ask the user to switch**. This stage never switches branches, never stashes, and never touches the working tree — rules in `references/branch.md`. 3. **The current state is always the remote branch `origin/{來源分支}`, never the local one.** The working directory's HEAD must point at the same commit as `origin/{來源分支}`; behind, ahead or diverged all mean you would be analysing code that is not what the remote holds. Report the gap (`git rev-list --left-right --count origin/{來源分支}...HEAD`) and stop — this stage never switches branches, never stashes, never pulls and never touches the working tree. Rules in `references/branch.md`.
4. Record the confirmed branch and its head sha on the analysis page. Completion condition: the user has confirmed the branch explicitly; never infer it from the current checkout alone. 4. Record the confirmed branch and the head sha **of `origin/{來源分支}`** on the analysis page. Completion condition: the user has confirmed the branch explicitly; never infer it from the current checkout alone.
3. Read `PLAN_CONTENTS` via `jsc-gitea:wiki` for plans whose status is the literal 「未分析」 (name and HASH), and read `ANALYZE_CONTENTS` for existing analyses. 3. Read `PLAN_CONTENTS` via `jsc-gitea:wiki` for plans whose status is the literal 「未分析」 (name and HASH), and read `ANALYZE_CONTENTS` for existing analyses.
4. Let the user choose per `jsc-ask:ask` rules: **extend an existing analysis** or **analyze a new plan**. State the impact scope on every option. 4. Let the user choose per `jsc-ask:ask` rules: **extend an existing analysis** or **analyze a new plan**. State the impact scope on every option.
5. Analyze the plan page's user stories one by one against the **current state**, **questioning until consensus** per `references/consensus.md` (the single authority for both planning and analysis): every answer produces the next question, and consensus needs both no output-changing unknown **and** the user's explicit confirmation. Never assume a missing detail, and never start the WBS while any item is still open. Current state means: 5. Analyze the plan page's user stories one by one against the **current state**, **questioning until consensus** per `references/consensus.md` (the single authority for both planning and analysis): every answer produces the next question, and consensus needs both no output-changing unknown **and** the user's explicit confirmation. Never assume a missing detail, and never start the WBS while any item is still open. Current state means:
1. Every file in the working directory, on the branch confirmed in step 2. 1. Every file in the working directory, at the commit `origin/{來源分支}` points to (verified in step 2).
2. **Reuse existing methods and endpoints whenever possible**: 2. **Reuse existing methods and endpoints whenever possible**:
- Check the `REPO_{HASH}` inventory page first. Re-inventory when the feature or endpoint is missing, or when the recorded commit sha differs from the current one. - Check the `REPO_{HASH}` inventory page first. Re-inventory when the feature or endpoint is missing, or when the recorded commit sha differs from the current one.
- Re-inventory **MUST run as a sub agent**: analyze the repository's features and endpoints, attach the current commit sha, write back to `REPO_{HASH}` with `templates/repo-page.md`, and update `REPO_CONTENTS` per `templates/repo-contents.md`. - Re-inventory **MUST run as a sub agent**: analyze the repository's features and endpoints, attach the current commit sha, write back to `REPO_{HASH}` with `templates/repo-page.md`, and update `REPO_CONTENTS` per `templates/repo-contents.md`.
+4 -4
View File
@@ -16,7 +16,7 @@ All wiki reads and writes go through `jsc-gitea:wiki`.
3. **Never claim a capability tag you have not verified with that script**, and never substitute your own judgement for its verdict. Non-zero exit = blocked: relay the script's message verbatim, stop the skill, do nothing else this turn. Do not run `unlock` to get past the gate; only the user may decide that. 3. **Never claim a capability tag you have not verified with that script**, and never substitute your own judgement for its verdict. Non-zero exit = blocked: relay the script's message verbatim, stop the skill, do nothing else this turn. Do not run `unlock` to get past the gate; only the user may decide that.
4. Exit 0 means the stage is locked. From now until the next stage's gate runs, the sdlc-gate hook blocks every prompt whose model stops satisfying the tags. 4. Exit 0 means the stage is locked. From now until the next stage's gate runs, the sdlc-gate hook blocks every prompt whose model stops satisfying the tags.
2. **Confirm the target branch** — do this **before writing any file**: 2. **Confirm the target branch** — do this **before writing any file**:
1. Report the current branch, whether the working tree is clean, and which of `origin/develop` / `origin/master` exist, plus the remote default branch resolved per `references/branch.md`. 1. Run `git fetch --prune origin` first — every `origin/...` reference is stale cache without it. Then report the current branch, whether the working tree is clean, which of `origin/develop` / `origin/master` exist, and the remote default branch resolved per `references/branch.md`. **Branches are always the remote ones; local branches are never the basis.**
2. Ask per `jsc-ask:ask` rules which branch this work merges into; state the impact scope on every option (the answer decides the PR target and, when it collides with the current branch, forces a new working branch). 2. Ask per `jsc-ask:ask` rules which branch this work merges into; state the impact scope on every option (the answer decides the PR target and, when it collides with the current branch, forces a new working branch).
3. Uncommitted changes in the working tree → warn first and let the user commit or back them up; never discard them. 3. Uncommitted changes in the working tree → warn first and let the user commit or back them up; never discard them.
4. Apply `references/branch.md` to the confirmed target: source branch and target branch sharing a name means creating a new working branch instead of committing on the target; report the resulting branch name. 4. Apply `references/branch.md` to the confirmed target: source branch and target branch sharing a name means creating a new working branch instead of committing on the target; report the resulting branch name.
@@ -30,13 +30,13 @@ All wiki reads and writes go through `jsc-gitea:wiki`.
3. Chose 由使用者輸入 → produce exactly what the user described; do not force the API document layout onto it. 3. Chose 由使用者輸入 → produce exactly what the user described; do not force the API document layout onto it.
4. Record the confirmed type in the analysis page's 交付型別 column and save it before starting the todos. 4. Record the confirmed type in the analysis page's 交付型別 column and save it before starting the todos.
7. **Create the worktree — before touching any code**. Full rules in `references/branch.md`: 7. **Create the worktree — before touching any code**. Full rules in `references/branch.md`:
1. Read the **source branch** and the repositories involved from the analysis page. Every code change happens inside the worktree; the main working directory's branch and working tree stay untouched. 1. Run `git fetch --prune origin`, then read the **source branch** and the repositories involved from the analysis page. The worktree is built from `origin/{來源分支}` — **never from a local branch of the same name**, which may be behind, ahead or diverged. Every code change happens inside the worktree; the main working directory's branch and working tree stay untouched.
2. Path: `{工作目錄}/.worktree/{分析頁 HASH}/{repo}` — the HASH without the `ANALYZE_` prefix, the repo name without its owner. One worktree per repository, all under the same HASH directory. 2. Path: `{工作目錄}/.worktree/{分析頁 HASH}/{repo}` — the HASH without the `ANALYZE_` prefix, the repo name without its owner. One worktree per repository, all under the same HASH directory.
3. **Ask per `jsc-ask:ask` rules how to handle the branch**, with the two fixed options: create a new working branch off the source branch (`git worktree add -b {工作分支} {路徑} {來源分支}`), or check the source branch out directly (`git worktree add {路徑} {來源分支}`). State the impact scope on each. **Never assume, never skip the question.** 3. **Ask per `jsc-ask:ask` rules how to handle the branch**, with the two fixed options: create a new working branch off the remote source branch (`git worktree add -b {工作分支} {路徑} "origin/{來源分支}"`), or check the source branch out with remote tracking (`git worktree add --track -b {來源分支} {路徑} "origin/{來源分支}"`). State the impact scope on each. **Never assume, never skip the question.**
4. **Quote every branch name and path**: source branches carry Chinese characters, spaces and multiple slashes (for example `feat/一址通/查地址/完整版/P2`), and an unquoted argument gets split. 4. **Quote every branch name and path**: source branches carry Chinese characters, spaces and multiple slashes (for example `feat/一址通/查地址/完整版/P2`), and an unquoted argument gets split.
5. No local clone of that repository → stop and ask the user for its path; never clone on your own initiative and never guess the location. 5. No local clone of that repository → stop and ask the user for its path; never clone on your own initiative and never guess the location.
6. Add `.worktree/` to that repository's `.git/info/exclude` — never edit the user's shared `.gitignore`. 6. Add `.worktree/` to that repository's `.git/info/exclude` — never edit the user's shared `.gitignore`.
7. Report the worktree path, the checked-out branch and the source branch. Completion condition: every involved repository has a worktree and you have reported all of them. 7. Report the worktree path, the checked-out branch, the source branch and the commit sha `origin/{來源分支}` pointed at — that sha is this implementation's starting point and must stay traceable. Completion condition: every involved repository has a worktree and you have reported all of them.
8. List every open item of the work package and implement them **one at a time**, **inside the worktree**: 8. List every open item of the work package and implement them **one at a time**, **inside the worktree**:
- Follow the TDD loop: red before green, one slice at a time; rules and anti-patterns in `references/tdd.md` (refactoring belongs to the review stage). - Follow the TDD loop: red before green, one slice at a time; rules and anti-patterns in `references/tdd.md` (refactoring belongs to the review stage).
- After each item, flip its `[ ]` to `[x]` on the analysis page and save to the wiki before starting the next item. - After each item, flip its `[ ]` to `[x]` on the analysis page and save to the wiki before starting the next item.
+1 -1
View File
@@ -17,7 +17,7 @@ All wiki reads and writes go through `jsc-gitea:wiki`.
4. Exit 0 means the stage is locked. Run this gate only when the stage changes; inside the maintenance stage the lock already covers every project, so never re-gate between projects. 4. Exit 0 means the stage is locked. Run this gate only when the stage changes; inside the maintenance stage the lock already covers every project, so never re-gate between projects.
2. Read `MAINTAIN_CONTENTS` via `jsc-gitea:wiki` and filter projects **still inside their maintenance window**: start date ≤ today, and (end date is NULL or ≥ today). 2. Read `MAINTAIN_CONTENTS` via `jsc-gitea:wiki` and filter projects **still inside their maintenance window**: start date ≤ today, and (end date is NULL or ≥ today).
3. Every project **MUST run as a sub agent** with this flow: 3. Every project **MUST run as a sub agent** with this flow:
1. Switch the project to the `develop` branch, falling back to `master`, and pull to latest. 1. Run `git fetch --prune origin`, then switch the project to `develop`, falling back to `master`, and bring it up to `origin/{該分支}` — the remote is the basis, never the local branch. Local and remote diverged → report and skip that project; never `pull --rebase`, `reset` or discard anything on your own.
2. Propose **at least five** maintenance methods and apply the ones that fit the project, for example: 2. Propose **at least five** maintenance methods and apply the ones that fit the project, for example:
- dependency updates (reuse `jsc-pkg:pkg-update`) - dependency updates (reuse `jsc-pkg:pkg-update`)
- security vulnerability scan and patching - security vulnerability scan and patching
+1 -1
View File
@@ -7,7 +7,7 @@
- HASH:`{HASH}` - HASH:`{HASH}`
- 對應計畫:[PLAN_{HASH}]({PLAN 頁絕對網址}) - 對應計畫:[PLAN_{HASH}]({PLAN 頁絕對網址})
- 存取庫:`{owner}/{repo}` - 存取庫:`{owner}/{repo}`
- 來源分支:`{使用者確認的分支}`(head sha:`{sha}`) - 來源分支:`origin/{使用者確認的分支}`(head sha:`{sha}`,取自遠端)
- 狀態:未完成 <!-- 未完成 | 已完成 --> - 狀態:未完成 <!-- 未完成 | 已完成 -->
- 建立時間:{yyyy-MM-dd HH:mm:ss} - 建立時間:{yyyy-MM-dd HH:mm:ss}