文
文档版本快照
作者:鹿Sir办公效率v1
文档版本快照管理,为非技术用户提供目录级版本控制。每完成一轮文档修改(PRD、需求文档、方案等)后自动保存带版本号的快照;支持列出版本历史、秒级回退到任意版本、对比两版差异。当用户提到"存个版本、保存快照、版本号、回到第几版、回退、撤销修改、版本历史"时使用。适用于 macOS 与 Windows,零依赖。触发词:文档版本、快照保存、版本回退、版本历史。
下载量
399
点赞
98
价格
免费
技能文档
---
name: doc-snapshot
title: 文档版本快照
category: 办公效率
description: 文档版本快照管理,为非技术用户提供目录级版本控制。每完成一轮文档修改(PRD、需求文档、方案等)后自动保存带版本号的快照;支持列出版本历史、秒级回退到任意版本、对比两版差异。当用户提到"存个版本、保存快照、版本号、回到第几版、回退、撤销修改、版本历史"时使用。适用于 macOS 与 Windows,零依赖。触发词:文档版本、快照保存、版本回退、版本历史。
---
# 文档版本快照
为非技术用户(产品经理等)提供目录级版本管理:每次修改自动留快照,可秒级精确回退,不使用 Git。
## 核心机制
快照库位于目标目录下的 `.snapshots/`:
```
目标目录/
├── .snapshots/
│ ├── data/
│ │ ├── 0001/ # 全量版:完整文件副本(严禁混入任何其他文件)
│ │ └── 0002/ # 增量版(仅 Windows 产生):manifest.json + 变化文件副本
│ ├── meta/
│ │ ├── 0001.json # 序号 1 的元数据(显示版本号 + 时间 + 改动说明 + 类型)
│ │ └── 0002.json
│ └── 操作日志.md # 人类可读的操作台账(只增不减,供用户直接翻阅)
└── (用户的工作文件)
```
六条铁律:
1. **快照不可变**:`.snapshots/data/` 下的内容一旦写入,只新增版本,永不修改或删除已有版本(用户明确要求清理时除外)
2. **回退必留后路**:执行 restore 前,必须先把当前状态保存为快照(描述标明"回退前现场"),保证任何回退都可撤销
3. **描述必写清**:每版元数据(`meta/NNNN.json`)的 name 与 desc 必须写清——name 是用户引用的版本号,desc 是一句人类可读的改动摘要,这是用户回看历史的唯一线索
4. **元数据与数据分离**:版本元数据只放 `meta/NNNN.json`,严禁放进 `data/NNNN/` 内部——全量版 restore 会把 `data/NNNN/` 整个镜像回工作目录,混入的文件会污染用户目录;增量版目录内只允许 manifest.json 与变化文件副本
5. **操作日志只增不减**:`.snapshots/操作日志.md` 每次保存、回退、清理都必须在表格顶部追加一行记录;即使删除了旧版本,日志记录也永不删除——它是用户不问 AI 就能翻阅全部操作的唯一凭证
6. **增量版严禁直接镜像恢复**:增量版(目录内有 manifest.json)必须按"镜像其基础全量版 → 覆盖增量文件 → 应用删除清单"三步重建;直接镜像增量版目录会让工作目录丢掉所有未变化文件
## 技能工作流
### 步骤1:确定平台与目标目录
- 目标目录 = 当前正在编辑的文档目录(当前 workspace,或用户明确指定的目录)
- 平台检测:优先从环境信息判断;不确定时执行 `uname -s`(`Darwin` → macOS;报错或返回 `MINGW*`/`CYGWIN*` → Windows)
- 复制策略随平台:macOS 全部全量克隆(零空间);Windows 里程碑全量 + 过程版增量(详见 save)
### 步骤2:保存快照(save)
触发时机:
- **首次使用**:目录尚无 `.snapshots/` 时,在动手修改任何文件**之前**先保存(name 固定 `v1`,desc 写"初始版本"),保住改前原始状态
- **自动存(过程版本)**:每完成一轮文档修改(一个需求点落地)后主动执行,无需用户提醒
- **手动存(里程碑版本)**:用户说"存个版本 / 保存快照 / 存档"时
步骤:
1. 若 `.snapshots/data/` 不存在 → 本次为首个版本,name 固定 `v1`,desc 写"初始版本"
2. 序号 = 现有最大序号 + 1,目录名四位零填充(如 `0012`);序号只用于存储定位、永远递增,用户无需感知
3. 计算显示版本号 name(用户看到并引用的就是它):
- **手动存**(用户开口要求保存)→ 主版本 +1:上一版是 `v1.3` → 新版 `v2`;上一版是 `v2` → 新版 `v3`
- **自动存**(AI 改完自动留痕、回退前现场)→ 主版本不变、次版本 +1:上一版是 `v1` → 新版 `v1.1`;上一版是 `v1.2` → 新版 `v1.3`;上一版是 `v2` → 新版 `v2.1`
- 铁则:**上一版 = 序号最大的版本,版本号永远向前、永不复用**——即使刚发生过回退。如最新是 v11、回退到 v9.2 后继续工作:回退现场存为 v11.1,后续依次 v11.2、v11.3……绝不产生新的 v9.3(同号不同内容会让"回到 v9.3"产生歧义)
4. 确定版本类型(type):
- macOS:所有版本均为**全量版**(克隆复制零空间,无需增量)
- Windows:手动存(里程碑)为**全量版**;自动存为**增量版**(基于最近一个全量版),但变化文件总量超过其基础全量版大小的 50% 时,自动升级为**全量版**
5. 按平台与类型执行复制命令(见下)
6. 写入 `.snapshots/meta/0012.json`(含 type;增量版含 base)
7. 更新操作日志(格式见下方"操作日志"小节),在表格顶部插入一行:手动存操作列写"保存(里程碑)",自动存写"保存"
8. 向用户汇报:`已保存 v2.1:{改动摘要}`
macOS(APFS 克隆复制,系统自带 cp):未变化的文件与工作目录共享存储块,**几乎不占额外空间**,只有真正变化的文件才占新空间;克隆是写时复制,修改任一方互不影响,历史绝不因原地编辑被污染。
```bash
mkdir -p ".snapshots/data/0012"
find . -mindepth 1 -maxdepth 1 ! -name '.snapshots' ! -name '.DS_Store' ! -name 'Thumbs.db' ! -name '~$*' -exec cp -Rc {} ".snapshots/data/0012/" \;
find ".snapshots/data/0012" \( -name '.DS_Store' -o -name 'Thumbs.db' -o -name '~$*' \) -delete
```
若 `cp -c` 报错(旧式 HFS+ 等卷不支持克隆),退回 rsync 全量复制:
```bash
rsync -a --exclude='.snapshots' --exclude='.DS_Store' --exclude='~$*' --exclude='Thumbs.db' ./ ".snapshots/data/0012/"
```
Windows(robocopy + PowerShell,系统自带,在 PowerShell 执行):
全量版(里程碑、以及变化量超基础版 50% 的自动存):
```powershell
robocopy "." ".snapshots\data\0012" /E /XD .snapshots /XF "~$*" .DS_Store Thumbs.db /NJH /NJS /NDL /NFL
```
⚠️ robocopy 退出码 0–7 均为成功(1 = 有文件被复制),≥ 8 才是失败,勿误判。
增量版(自动存的常规情况,三步):设最近全量版序号对应的目录为 B(如 `0001`)。
⚠️ 增量清单 = 工作目录相对基础全量版的**全部当前差异**——包含之前轮次改过但尚未还原的文件(如 v1.1 改过 001、本轮又改 002,则 v1.2 的清单同时含 001 与 002 的最新内容),**严禁只存本轮改动**。这样每个增量版都能配合基础版一步独立恢复,clean 也可安全删除任何一版。
① 找出工作目录相对基础版的变化(按相对路径 + 大小 + 修改时间对比,输出 ADDED / DELETED / CHANGED 三组清单):
```powershell
$base = ".snapshots\data\0001"
$baseFiles = Get-ChildItem $base -Recurse -File | ForEach-Object { @{ Path = $_.FullName.Substring((Resolve-Path $base).Path.Length + 1); Size = $_.Length; Time = $_.LastWriteTimeUtc } }
$workFiles = Get-ChildItem "." -Recurse -File | Where-Object { $_.FullName -notmatch '\\\.snapshots\\' -and $_.Name -notlike '~$*' -and $_.Name -ne '.DS_Store' -and $_.Name -ne 'Thumbs.db' } | ForEach-Object { @{ Path = $_.FullName.Substring((Resolve-Path ".").Path.Length + 1); Size = $_.Length; Time = $_.LastWriteTimeUtc } }
$baseMap = @{}; $baseFiles | ForEach-Object { $baseMap[$_.Path] = $_ }
$workMap = @{}; $workFiles | ForEach-Object { $workMap[$_.Path] = $_ }
"=== ADDED ==="; ($workFiles | Where-Object { -not $baseMap.ContainsKey($_.Path) } | ForEach-Object { $_.Path })
"=== DELETED ==="; ($baseFiles | Where-Object { -not $workMap.ContainsKey($_.Path) } | ForEach-Object { $_.Path })
"=== CHANGED ==="; ($workFiles | Where-Object { $baseMap.ContainsKey($_.Path) -and ($baseMap[$_.Path].Size -ne $_.Size -or $baseMap[$_.Path].Time -ne $_.Time) } | ForEach-Object { $_.Path })
```
② 判断:若 CHANGED + ADDED 文件大小总和超过基础版大小(`(Get-ChildItem $base -Recurse -File | Measure-Object Length -Sum).Sum`)的 50% → 改存全量版(上方全量命令)。否则:新建 `.snapshots\data\0012` 目录,写入 manifest.json(内容见③),再把 CHANGED + ADDED 的文件按相对路径逐个复制进去(目标子目录不存在时先 `New-Item -ItemType Directory` 创建):
```powershell
New-Item -ItemType Directory -Path ".snapshots\data\0012" -Force | Out-Null
Copy-Item "会员积分系统PRD.md" -Destination ".snapshots\data\0012\会员积分系统PRD.md" -Force
```
③ manifest.json(增量版专用,放 `data/0012/manifest.json`):
```json
{
"base": 1,
"changed": ["会员积分系统PRD.md"],
"added": ["积分商城原型说明.md"],
"deleted": []
}
```
空清单为合法边界情况:若三组清单全为空(典型场景:里程碑 v2 存完后未做任何修改就要求回退——回退前现场与其 base 零差异),照常建目录并写入三组均为空数组的 manifest.json(目录内仅有 manifest.json),meta 照常记录;恢复时等价于直接镜像基础版。严禁因清单为空而跳过建版或误判对比出错。
若目标目录含明显的构建/依赖产物(如 node_modules、dist),一并追加到排除列表。
空间说明:macOS 克隆副本未变化的文件不占新空间;Windows 无克隆机制,采用"里程碑全量 + 过程版增量"——磁盘只随里程碑数线性增长,AI 的中间修改只存变化量,几十轮对话也吃不满磁盘。含大量视频、安装包、构建产物的目录不建议使用。
`.snapshots/meta/0012.json` 内容(时间用 Shell 取:mac `date '+%Y-%m-%d %H:%M'`,win `Get-Date -Format 'yyyy-MM-dd HH:mm'`):
```json
{
"seq": 12,
"name": "v2.1",
"type": "delta",
"base": 11,
"time": "2026-09-08 14:30",
"desc": "把登录方式从手机号验证码改为扫码,删除了短信模块"
}
```
(全量版则 `"type": "full"` 且无 base 字段)
### 操作日志(.snapshots/操作日志.md)
人类可读的操作台账,供用户不问 AI、直接用肉眼翻阅全部历史。首行固定表头,每次操作在表格**顶部**(表头下方)插入一行,只增不减:
| 时间 | 版本 | 操作 | 说明 |
|---|---|---|---|
| 2026-09-08 14:30 | v2.1 | 保存 | 把登录方式从手机号验证码改为扫码 |
| 2026-09-08 14:00 | v2 | 保存(里程碑) | 登录方案定稿 |
| 2026-09-08 13:58 | v1.1 | 回退 | 从 v2.1 回退到 v1.1,回退前现场已存为 v2.2 |
操作类型共四种:**保存**(AI 自动留痕)、**保存(里程碑)**(用户主动要求)、**回退**(说明里注明从哪版回到哪版、现场存为了哪版)、**清理**(删除旧版本,记录仍保留)。
### 步骤3:查看版本历史(list)
一条命令批量读取全部元数据(mac:`cat .snapshots/meta/*.json`;win:`Get-Content .snapshots\meta\*.json`),按 seq 从大到小排列,表格输出(大版本是用户标记的里程碑,小版本是 AI 自动留痕):
| 版本 | 时间 | 改动说明 |
|---|---|---|
| v2.1 | 09-08 14:30 | 调整退货审批流,增加财务节点 |
| v2 | 09-08 14:00 | 里程碑:登录方案定稿 |
| v1.1 | 09-08 10:12 | 新增会员积分需求 |
| v1 | 09-07 18:00 | 初始版本 |
用户只是想看上一版内容而不回退时,直接读取对应快照目录里的文件展示,不改动工作目录。
### 步骤4:回退版本(restore)
触发:用户说"回到 v1.2 / 回到第 X 版 / 回退到 / 撤销刚才的修改"。
流程(顺序不可乱):
1. list 展示版本历史,与用户确认目标版本(用户已明确指定版本号时跳过),由目标版本的 name 定位其序号目录(如 `v1.2` → `data/0003/`)
2. **先 save 当前状态**(按自动存规则计版本号),desc 固定写:`回退到 {目标name} 前的现场`
3. 按目标版本类型执行恢复(见下):全量版直接镜像;增量版三步重建
4. 汇报:已回退到 {目标name}(时间 + 改动说明),当前目录内容与该版本完全一致
5. **上下文对齐(必做)**:回退只还原文件,对话记忆仍停留在回退前的最新状态——必须明确告知用户这一点,并主动询问:“接下来是基于 {目标name} 开新方向,还是重做刚才回退掉的内容?”用户本轮的回答是后续所有修改的基准;回退后的第一轮修改前必须重新读取文件当前内容,严禁凭回退前的对话记忆直接写入(防止按旧认知覆盖刚恢复的文件)
6. 更新操作日志:顶部插入 `| {时间} | {目标name} | 回退 | 从 {回退前name} 回退到 {目标name},回退前现场已存为 {现场name} |`
全量版恢复(目标目录内无 manifest.json,直接镜像):
```bash
# macOS
rsync -a --delete --exclude='.snapshots' ".snapshots/data/0003/" ./
```
```powershell
# Windows
robocopy ".snapshots\data\0003" "." /MIR /XD .snapshots /NJH /NJS /NDL /NFL
```
增量版恢复(目标目录内有 manifest.json,三步顺序不可乱):设目标增量版序号目录为 D(如 `0007`)、manifest 中 base 指向的基础全量版为 B(如 `0003`)。
```bash
# macOS
rsync -a --delete --exclude='.snapshots' ".snapshots/data/0003/" ./ # ① 先镜像恢复基础全量版
rsync -a --exclude='manifest.json' ".snapshots/data/0007/" ./ # ② 覆盖增量文件(不删除多余文件)
# ③ 按 manifest.json 的 deleted 清单逐个删除(rm -f "文件路径")
```
```powershell
# Windows
robocopy ".snapshots\data\0003" "." /MIR /XD .snapshots /NJH /NJS /NDL /NFL # ① 先镜像恢复基础全量版
robocopy ".snapshots\data\0007" "." /E /XF manifest.json /NJH /NJS /NDL /NFL # ② 覆盖增量文件(不删除多余文件)
# ③ 按 manifest.json 的 deleted 清单逐个删除(Remove-Item "文件路径" -Force)
```
"撤销刚才 AI 的修改" = 回退到最新一版的前一版。
⚠️ 镜像命令会删除目标端多余文件使目录与快照完全一致。排除规则(保护 `.snapshots` 自身)严禁去掉,否则快照库会被删除。
内容校验守则(确认改动生效、验证恢复结果等任何需要校验文件内容的场合,双平台适用):
- 优先用**文件 hash 对比**(mac `shasum "文件"`,win `(Get-FileHash "文件").Hash`)或 **ASCII 特征串**(如 `Select-String '\+100'`)验证内容,**严禁依赖中文正则/关键词 pattern**——经终端转发的 PowerShell 命令里,中文 pattern 可能因控制台编码(GBK)乱码而假阴性(实际匹配却返回 False);中文文件内容本身与中文路径传参不受影响
- 外部命令(rsync/robocopy/cp)改完文件后,重新读取文件时可能短暂显示缓存的旧内容,与 hash 结果矛盾时**一律以 hash 为准**,勿误判为恢复失败(IDE 缓存现象,非 skill 问题)
### 步骤5:对比两版(diff)
macOS:
```bash
diff -rq ".snapshots/data/0002" ".snapshots/data/0003"
```
Windows:
```powershell
robocopy ".snapshots\data\0002" ".snapshots\data\0003" /L /E /NJH /NJS /NDL
```
输出为文件级差异列表,需汇总为业务语言汇报,例如:"这一版主要改了《PRD-登录模块》,另新增 2 张原型图"。
若参与对比的版本是增量版(目录内有 manifest.json):先把该版重建到临时目录再对比——镜像其基础全量版到 `.snapshots/tmp/`、覆盖增量文件(排除 manifest.json)、应用删除清单,对比完成后删除 `.snapshots/tmp/`。
### 步骤6:清理旧版本(clean,仅用户明确要求时执行)
磁盘空间不足且用户明确要求删除某些旧版本时,成对删除对应的 `.snapshots/data/NNNN/` 目录与 `.snapshots/meta/NNNN.json`(各版本相互独立,无全局索引)。执行前列出版本让用户确认,并提示:删除后该版本无法恢复。建议始终保留初始版(v1)与最近 3 个版本。⚠️ 删除全量版前必须检查:若仍有增量版的 base 指向它,该全量版与其全部增量版须一起删除(或都不删),否则增量版会失去基础无法恢复。删除后,在操作日志顶部插入:`| {时间} | — | 清理 | 删除了版本 {name 列表} |`(日志记录保留,不随版本删除)。
## 交互规范
- 所有汇报使用业务语言,不出现 rsync、robocopy、镜像等技术词汇
- 每轮修改完成的汇报末尾附当前显示版本号(如 v2.1),不向用户提及内部序号
- 用户要回退但说不清版本时,先展示最近 5 版供其选择
- 回退后的第一轮修改:动手前必须重新读取目标文件当前内容,以文件实际内容为准,严禁凭回退前的对话记忆直接写入;用户未说明方向时先确认“基于回退后的版本继续,还是重做回退掉的内容”
- 用户想自己翻历史时,告知可直接打开 `.snapshots/操作日志.md`(无需问 AI)使用说明
# 文档版本快照 给非技术用户的目录级"后悔药":每轮文档修改自动存带版本号的快照,一句话回退到任意版本,秒级完成、逐字精确,不依赖 Git。 ## 使用 直接在对话里说: - 「存个版本」——保存里程碑快照 - 「版本历史」——列出所有版本与改动说明 - 「回到 v1.2」——秒级回退(回退前自动留存现场) - 「对比 v2 和 v3」——输出两版差异 ## 工作原理 在工作目录下维护 `.snapshots/` 快照库(全量/增量版本数据、JSON 元数据、人类可读的操作日志)。macOS 用 APFS 克隆复制做到全量快照几乎不占空间;Windows 用「里程碑全量 + 过程版增量」控制磁盘占用。
支持平台:Qoder · QoderWork · Claude · Codex 等 AI 编程助手