# 看过去和整体回滚

看任何文件夹、文件在某一刻的样子，改过名或删掉的也行；一次调用把整个文件夹退回去，这一步本身也能再撤回。

每次保存都是一个版本，每个改动都记在[变更日志](/docs/changes)里，所以空间记得自己在任何时刻的样子。你可以看 agent 动手之前文件夹是什么样，找回后来改了名或删掉的文件，也可以把整个文件夹退回去。

## 时刻怎么写

凡是带 `as_of` 的地方，时刻可以写成：

| 写法 | 例子 | 意思 |
|---|---|---|
| 时间 | `2026-11-15T09:30:00Z` | 这个时间点及之前的最后一次改动 |
| 多久以前 | `-2h`、`-90m` | 同上，从现在往回算 |
| 日志序号 | `1042` | 正好是这次改动之后 |

回答里带 `Sidespace-As-Of-Seq`，就是这个时刻对应的日志序号。用这个序号再查一次，结果完全一样，哪怕同一秒里还有别的改动。

## 看过去的样子

```sh tab=CLI
sidespace ls "Film A" /Ep01 --as-of -2h                   # 两小时前文件夹里有什么
sidespace get "Film A" /Ep01/script.md ./old.md --as-of -2h
```

```sh tab=curl
curl -H "Authorization: Bearer $SIDESPACE_TOKEN" \
  "$SIDESPACE_URL/v1/spaces/$SPACE/paths/Ep01/script.md?as_of=-2h"
curl -H "Authorization: Bearer $SIDESPACE_TOKEN" \
  "$SIDESPACE_URL/v1/spaces/$SPACE/nodes/$FOLDER/children?as_of=2026-11-15T09:30:00Z"
```

```ts tab=TypeScript
const then = await side.list("Film A", "/Ep01", { asOf: "-2h" });
const old = await side.download("Film A", "/Ep01/script.md", { asOf: "-2h" });
```

```python tab=Python
then = side.list("Film A", "/Ep01", as_of="-2h")
with side.open("Film A", "/Ep01/script.md", as_of="-2h") as r:
    old = r.read()
```

- `GET …/paths/{path}`、`GET …/nodes/{nid}` 和 `GET …/nodes/{nid}/children` 都可以带 `?as_of=`（或 `Sidespace-As-Of` 头）。路径按当时的样子查，所以用旧名字也能找到文件。
- 节点显示的是当时的当前版本，用它的 `head_version_id` 照常下载。
- 永久删除的文件没有过去；其余的，包括回收站里的，都能读到。

## 把文件夹退回去

回滚把文件夹恢复成某一刻的样子。先用演练（dry run）看一眼会改什么：

```sh tab=CLI
sidespace rewind "Film A" /Ep01 --to -2h --dry-run   # 先看会改什么
sidespace rewind "Film A" /Ep01 --to -2h
```

```sh tab=curl
curl -X POST -H "Authorization: Bearer $SIDESPACE_TOKEN" -H "Content-Type: application/json" \
  "$SIDESPACE_URL/v1/spaces/$SPACE/nodes/$FOLDER/rewind" -d '{"as_of": "-2h", "dry_run": true}'
```

```ts tab=TypeScript
const plan = await side.rewind("Film A", "/Ep01", "-2h", { dryRun: true });
for (const c of plan.changes) console.log(c.action, c.path, c.from_path ?? "");
```

```python tab=Python
plan = side.rewind("Film A", "/Ep01", "-2h", dry_run=True)
```

回答逐条列出改动：

| `action` | 做什么 |
|---|---|
| `restore` | 把文件的旧内容存成新版本。内容没变的文件不动 |
| `undelete` | 删掉的文件或文件夹从回收站恢复 |
| `move` | 后来移走或改名的放回原处。原来的名字被占了就换一个不重复的名字，`note` 里会说明 |
| `trash` | 当时没有、后来才有的放进回收站 |
| `missing` | 当时有、但已经永久删除的文件，找不回来 |

- 回滚在一个事务里完成，每一步都是普通的、记进日志的改动，所以什么都不会丢，回滚本身也能再回滚。
- 演练会把同样的事做一遍再撤销，所以它报告的就是真正执行时会发生的改动。
- 需要对这个文件夹和它要改的每一项都有编辑权限，令牌要有 `files:write`。
- 附加信息跟着版本走；评论不属于文件夹，不会被回滚。

## 通过 MCP 和 S3

- MCP 的 `list_folder` 和 `read_text` 接受 `as_of`，`rewind_folder` 用来回滚，它的说明要求 agent 先演练、给你看过再执行。见[在 Claude 里用](/docs/claude)。
- 通过 [S3 兼容接口](/docs/s3#版本和过去)，每个桶都开着版本控制；请求带 `x-sidespace-as-of` 头（或同名查询参数，用于预签名链接），列出和读取的就是桶在那一刻的样子。
