共用政策位置: docs/DISCOVERY.md、docs/WORKFLOW.md、
docs/LAUNCH-MIGRATION.md、docs/STANDALONE-ENTRY.md、docs/PROCESS.md、docs/using/README.md 和 docs/using/mirrors.md 屬於已解析的 Hatsu 外掛
根目錄,而非消費端儲存庫。在已安裝的表面上,請使用 ten 列出的絕對根目錄來讀取這些檔案(若找不到則透過該技能重新解析)。下方的相對連結標示原始位置;消費者缺少 docs/ 副本並不代表缺少政策,且不得觸發重複歸檔。絕不要在目標儲存庫中複製或憑空創造第二份政策。
Ao —— 分支,已同步
本質:操作系。 將分支與其基礎分支進行協調是 Git 端的操作,處理的不僅僅是你自己的成果,無論該 diff 的作者是哪種本質。
將基礎分支置於我之下,僅解決純文字衝突,然後將任何涉及意義的內容交給我。
Ao 是 $murasaki 的第一步、$aka 的第三步,
也是 $en 在 PR 落後時執行的步驟。它也可以獨立呼叫。
其整個紀律僅包含一個區別——文字 vs 意義——以及一個拒絕:它絕不推送它所產生的任何東西。
0. 獨立入口——已是完整的
Ao 已經直接讀取 checkout 內容,而非由呼叫者傳入。 § 2 在進行任何操作前先讀取狀態,§ 3 根據是否有任何內容已發佈來決定 rebase 或 merge,而 from <base> 會將基礎分支攜帶在 nen/workflow.json → branch.base 之下。docs/STANDALONE-ENTRY.md § 4 將其列為已是完整的;適用的條款為 P1 —— 若無複合技能執行它,則由 $ten ao 負責同步此階段的先決條件(ten § 6)——以及基礎分支需對解析至已擷取的 origin/ 參照,§ 3 已要求此行為。
獨立呼叫不影響 § 6 的任何規定:一個 語意 衝突是一個 G5 停止點,需顯示雙方內容,且絕不能透過選擇讓執行繼續進行的那一方來解決。Ao 仍然絕不推送、絕不強制推送,也絕不改寫已存在於遠端的提交。
交回控制權。 在有線執行流程中的下一步:需要分支保持最新的呼叫者——
$murasaki、$aka 或 $en。未推送任何內容,且在這次同步之前取得的證據,
若任何受追蹤的路徑有所變動,則已失效。
1. 呼叫方式
$ao [from <base>]
nen parse ao --grammar "from [<base>]" --line "<呼叫字串,去掉 $ao 前綴>"
已在 v0.3.0 版本驗證(docs/ab/ao.md § 2.1):from release/1.4 → base: release/1.4;單純的
from 會解析為子句缺失,退出碼 0。子句錨定在一個字面值之後,原因記錄在 $spiritual-message § 1。
若無子句,基礎分支預設為 nen/workflow.json → branch.base,預設值為 main,當該鍵值或
檔案不存在時。在擷取之前大聲說出基礎分支的名稱——一個靜默地同步到錯誤基礎分支的分支,
其產生的 diff 之後沒有人能讀懂。
缺少的引數或設定項目會直接被詢問並設定(missing-argument、
missing-configuration;WORKFLOW.md § 4 詢問、設定、繼續)。
2. 先讀取 checkout 狀態
nen wc classify --repo <路徑> --base <基礎分支> --json
已在 v0.3.0 驗證(docs/ab/ao.md § 2.2),--json 攜帶此技能在進行任何操作前所需的
確切資訊:state.branch、state.isTrunk、state.dirty、state.aheadOfBase、
state.existingCommitSubjects[]、state.uncommittedPaths[]。
nen wc classify 情況 | ao 的行為 |
|---|---|
must-move —— 在主要分支上 | 拒絕。 沒有什麼需要同步的:主要分支 就是 基礎分支。告知此情況並將控制權交給 $breath 或 $tensho,視情況而定 |
on-branch-dirty | 拒絕,並列出該指令列出的未提交路徑。 對未提交的變更進行 merge 或 rebase,要麼會被 Git 直接拒絕,要麼會將變更埋藏在一場無人能釐清的衝突中。請提交它($kokusen)或深思熟慮後 stash,然後重新執行 |
on-branch-clean | 繼續執行 § 3 |
nen wc classify不是衝突檢測器,而一個未完成的 merge 會被視為一般髒資料——已在v0.3.0驗證(docs/ab/ao.md§ 2.2)。 在未解決的 merge 內部執行時,它會回報on-branch-dirty,並將衝突路徑計入「未提交路徑」,對進行中的 merge 隻字未提。因此在分類之前先詢問 Git,絕不要直接讀取磁碟上的.git/(在連結工作目錄中.git是一個檔案):git rev-parse -q --verify MERGE_HEAD解析成功,或git rebase --show-current-patch退出碼為0(一個因衝突或edit而暫停的 rebase),表示先前的操作在此停止,這次執行會回報該狀態且不啟動任何新操作——絕不在其之上執行第二次操作,也絕不從此處重新執行wc catch-up,這會以 Git 的預設訊息提交一個 merge 且未經重新驗證的建構(§ 5)。探測的其他結果:1(一個暫停且無目前修補程式的 rebase,處於break或失敗的exec)不屬於 ao 的範疇,因此執行流程會回報它並附上 Git 自己的--continue/--abort提示,然後就此停止,絕不依賴 catch-up 來拒絕它,因為一個仍執行 nen 0.18.0 或 0.18.1 的主機不會這樣做(zheref/hatsu#182);128表示沒有 rebase,因此進行分類;其他任何情況則留給 § 3 的「未回答探測」行處理。
3. 決定操作——rebase 或 merge,由是否有內容已發佈來決定
當此分支上沒有任何內容已發佈時進行 rebase。當有內容已發佈時進行 merge。 改寫一個 其他人可能已經擷取過的提交,是唯一會讓他人付出額外工作的 Git 操作, 本地層級絕不這麼做。
nen wc catch-up --repo <路徑> --base <基礎分支> [--strategy rebase|merge|auto] [--dry-run] [--json]
該指令會先擷取,然後決定,而決定是依據 origin 現在說的話,
絕不依據這個 checkout 上次聽到的資訊。auto(ao 傳入的參數)會在分支上沒有任何內容存在於 @{upstream} 時執行 rebase,否則執行 merge;--strategy rebase|merge 僅在呼叫者有理由時指定其中一種,且必須明確說出理由。退出碼 0
會回報 {base, strategy, before, after, behindBefore, aheadBefore, noOp},而一個 noOp: true 仍然會連同兩個 SHA 一併回報,絕不會回報成「無事可做」。其他所有退出碼,根據 nen v0.20.0 定義:
| 退出碼 | 意義 | ao 的行為 |
|---|---|---|
1,且帶有 conflicted[] 非空的報告 | 發生衝突;會列印中止行 | § 4 接手處理 |
3,且報告中的 conflicted[] 路徑全部位於 nen/contract.json 的頂層 mechanical 區塊(v0.20.0) | 發生一個由 nen 分類為 manifest、changelog 或 mirror 的衝突;會列印中止行以及每個類別的指令,但皆不執行 | § 4 接手處理,並引用 nen 的類別與指令作為證據;§ 4 仍然會自己分類每個路徑 |
1,但無報告 | 擷取、狀態或 HEAD 讀取失敗,rebase 或 merge 失敗但無衝突,或 --continue 失敗 | 停止:逐字引用 nen 的 stderr 訊息,說明樹的狀態與 Git 留下的狀態一致;絕不執行 § 4 |
2,一個暫停於 break 或失敗的 exec 的 rebase(v0.18.2) | 不是 ao 的 rebase | 引用 nen 的訊息,該訊息會提示 git rebase --continue / --abort;絕不繼續或中止它 |
2,一個 Git 未回應的 rebase 探測(v0.18.2) | 可能根本沒有 rebase | 引用 nen 的訊息並停止,不指定任何 git 指令 |
2,其他任何情況 | 在進行任何修改前的拒絕:髒的工作目錄、--base 被 Git 拒絕、--strategy 與進行中的操作不符、Git 版本過舊不支援 --end-of-options、找不到儲存庫根目錄 | 逐字引用它並停止 |
| 任何其他退出碼 | 未預期 | 停止並引用它 |
strategy: merge→ 分支存在於遠端 → 將基礎分支 merge 進來。strategy: rebase→ 無任何內容已發佈 → 將分支重播到origin/<base>之上。
一個沒有東西可 rebase 的 rebase 仍然會改寫 SHA,這是預期的行為。 已在實際環境驗證: 一個已經直接位於
origin/<base>頂端的分支回應了「成功 rebase 並更新」,並將HEAD從c8826c7移動到84b0444——相同的樹、相同的訊息、新的提交 物件,因為 rebase 重播了提交,而不是發現沒有必要。在這裡且僅在這裡是無害的:§ 3 僅對未發佈的分支執行 rebase,因此被改寫的提交是沒有人擷取過的。但不能將其回報為「無事可做」—— § 7 會要求基礎分支及其解析後的 SHA,而一個在HEAD已變動的情況下說「沒有變更」的執行, 會讓之後所有對舊 SHA 的引用都默默錯誤。
用一行話從其報告中說出該指令選擇了哪個操作以及原因,並指出是哪次更新:
「已擷取 origin;分支存在於 @{upstream},因此使用 strategy: merge,而非 rebase。」
已於 nen
0.5版本退役,並於0.13版本被取代。 Merge 部分曾經透過nen pr cascade-main --repo <路徑> --trunk <基礎分支> --no-push(已在v0.5.0版本驗證,docs/ab/ao.md§ 已在 nen 0.5 版本退役)執行,而 rebase 部分在任何旗標下都沒有對應的指令。兩者現在皆由nen wc catch-up負責, 且該指令絕不推送。cascade-main保留其在 izanami 自動化表格中的mutating行, 包含--no-push,但已不再是 ao 所呼叫的內容。
4. 在解決任何衝突路徑之前,先分類所有衝突路徑
git -C <路徑> status --porcelain # 衝突行
git -C <路徑> diff --name-only --diff-filter=U # 衝突路徑,單獨列出
git -C <路徑> ls-files -u # 每個路徑有哪些階段
已在針對包含每種情況的建構 fixture 上驗證(docs/ab/ao.md § 2.4):
| Porcelain | 種類 | 存在的階段 |
|---|---|---|
UU | 雙方修改 —— 雙方都變更了同一個檔案 | 1 基礎, 2 我們的, 3 他們的 |
AA | 新增-新增 —— 雙方都建立了相同的路徑 | 2 我們的, 3 他們的;無基礎 |
UD / DU | 刪除-修改 —— 一方刪除了另一方編輯的內容 | 僅存活的側 |
DD, AU, UA | 較罕見的形式;用相同表格分類並命名 | 如 Git 所回報 |
nen wc catch-up --json在退出碼1或3時攜帶conflicted[],每個未合併路徑一個條目,包含ours和theirs的逐字內容(並且,從nen.wc.catch-up/v0.2開始,包含 nen 的class)。但它不包含 種類,因此上方的 porcelain 表格 仍需用於讀取該資訊,而 § 6 會完全按照指令列印的內容顯示ours/theirs。該指令自己的 規則是值得在適用之處引用的:它絕不選擇立場。
在解決任何路徑之前先分類所有路徑,並列印表格。 一個解決了前三條路徑卻發現第四條是語意衝突的執行流程, 已經在第一個三個路徑上耗費了維護者的信任。
5. 機械衝突,還是語意衝突
機械衝突 —— 解決方案是確定的,由儲存庫決定,而非由任何人選擇:
- 一個雙方都進行了追加的僅追加區域(例如 import 區塊、
.gitignore、changelog 列表)—— 保留兩者,按照檔案自身慣例的順序排列; - 一個由儲存庫重新產生的生成檔案或鎖定檔案(例如 lockfile、snapshot、mirror)——採用
基礎分支的版本並重新產生(Hatsu mirrors:
bash scripts/surface_mirror_regenerate.sh), 然後用宣告的建構來證明它(nen shu build;其 退出碼對應表與$rasengan§ 6 相同); - 純格式或空白字元的差異,無行為上的不同;
- 雙方做出的相同變更。
Hatsu 版本碰撞可能在乾淨的同步程式中存活下來: 平行的分支可能選擇了相同的號碼。
在每次同步之後,將兩個實際的 manifest(.claude-plugin/plugin.json 和
.codex-plugin/plugin.json)與最新的基礎分支進行比較。如果分支的版本等於或低於
基礎分支的版本,請在準備就緒前將兩者重新提升至嚴格高於該基礎分支的相同版本;同時更新
此工作現有 changelog.d/ 片段中的版本行。這是 Hatsu 的編寫工作,不是自動的 nen wc catch-up 重新提升。在下一個版本決定後,執行
bash scripts/plugin_version_refs.sh --from <舊版> --to <新版> --body-file <本機草稿> 來列出
受追蹤的參考和草稿行。加入 --write 來改寫宣告的受追蹤形式以及明確草稿行上的每個舊版本精確 token;
閱讀列印出的 review 行,這些行保持不變。
該輔助工具絕不會選擇版本、改寫產生的 mirror 或編輯遠端 PR。使用上述指令重新產生 mirrors,然後重新推導那些因同步而失效的正文事實:
| 正文事實 | 同步後重新推導 |
|---|---|
| 外掛版本 | 在提交版本提升後執行 git show HEAD:.claude-plugin/plugin.json 和 git show HEAD:.codex-plugin/plugin.json |
| HEAD 和基礎分支提交 | 在最終提交和擷取後執行 git rev-parse HEAD origin/<基礎分支> |
| 相對於基礎分支測量的數據(位元組、diff、覆蓋率、審查證據) | 針對新的基礎分支和最終 HEAD 重新測量 |
| Drive 行中的 PR 編號 | gh pr list --repo <擁有者/名稱> --state open --head <分支> --json number,url;使用回傳的當前 PR |
| Changelog 片段先決條件行 | 針對同步後的依賴合約和此工作的實際先決條件重新測量 |
檢視更新後的本機草稿,然後使用 nen pr edit-body 作為遠端寫入器。
針對新的基礎分支重新執行版本提升檢查;原始的基準點無法證明此比較。
語意衝突 —— 任何需要人來決定偏好哪個意圖的情況。UD/DU 永遠是語意衝突:
「已刪除」和「仍在編輯中」是兩種關於事物是否存在的信念,
沒有合併演算法可以持有這種信念。一個雙方都改變了相同行為的 UU 也是如此,
以及一個兩個檔案並非同一檔案的 AA。
教科書案例,已在實際環境驗證(
docs/ab/ao.md§ 2.4): 一個DU合併是