暂存与 apply 语义¶
暂存把 Job 的工作区改动留在写时复制的 upper 层。只有显式的 apply 才会改变目标工作区。因此文件改动在 apply 之前是可逆的:选择合入、丢弃,或分叉。
这里定义暂存契约,每条承诺对应 tests/semantics/stage-apply.md 中的一个用例,可用 just semantics 复现。操作流程见审查与应用。
承诺¶
| 承诺 | 含义 | 语义用例 |
|---|---|---|
| apply 前工作区不变 | 成功、非零退出或信号终止后,工作区的路径、类型、内容、权限位与链接目标都与初始状态一致,直到 apply | S-STAGE-001 |
| Job 读取自己的变更 | Job 能看到自己的写入、删除与重命名,而宿主工作区不变 | S-STAGE-002 |
| Review 表示净效果 | 清单等于净新增、删除与修改;创建后又删除的文件不出现 | S-STAGE-003 |
| 全部 apply 等价直接运行 | 暂存一个脚本后执行 apply --all,得到的树与直接在 workspace 中运行脚本一致 |
S-STAGE-004 |
| drop 后拒绝 apply | drop 保持工作区不变;之后的 apply 被拒绝且无效果 | S-STAGE-005 |
| 选择性 apply 只影响所选子树 | apply --path P 只改 P 及其后代;两个覆盖全部改动的选择性批次等价于一次 --all |
S-STAGE-006 |
| 重复 apply 无额外效果 | 对已应用的路径再次 apply 不改变工作区 | S-STAGE-007 |
| 冲突保留外部改动 | 目标是 apply 前被外部修改、新建或删除时,apply 被拒绝,外部状态完整保留 | S-STAGE-008 |
| 冲突批次整体无效果 | 所选路径中任一冲突时,本次 apply 不改变任何所选路径 | S-STAGE-009 |
| 未触碰路径的外部改动不阻止 apply | Agent 未触碰的路径被外部改动时,外部内容保留,且不阻止 apply | S-STAGE-010 |
| 删除目录保留外部新增 | Agent 删除了一个目录、外部写入者随后在其中新增文件时,apply 被拒绝 | S-STAGE-011 |
| apply 不越出工作区 | 暂存后某目录被替换为指向外部的链接时,apply 被拒绝,两边目录树都不变 | S-STAGE-012 |
| 返回值与效果一致 | 链接创建成功就留下链接;失败则不留下 | S-STAGE-013(见下方 macOS 已知缺口) |
| 可执行位与链接目标保留 | 可执行位与符号链接目标都被保留,且不解除链接 | S-STAGE-014 |
这些用例是未经人工审核的草稿。测试通过只说明实现满足脚本,不代表语义已评审。见测试与 semspec。
已知缺口¶
- S-STAGE-013 在 macOS 上是 XFAIL:macFUSE 在创建符号链接时可能返回 EPERM,尽管链接已创建。见已知限制。
- 重命名表现为删除加新增:审查清单没有单独的 rename 表示。
- 多文件 apply 对外部编辑器不是原子的:冲突检查先于写入;apply 期间应停止其他写入者。中断后,
apply-ledger.json让已准备的批次向前恢复。
不可逆的部分¶
暂存只覆盖工作区文件。以下影响绕过它,apply 和 drop 都无法撤销:
- 远程 API 调用、数据库写入、已发出的消息等外部影响;
- 通过
--mount SOURCE:write显式共享的宿主路径; - 已经 apply 的批次:drop 不会撤销它们。
HOME、VM 根目录等其他位置的写入见暂存与存储。