Snapshot
Snapshot 提供文件系统快照和差异比较功能。
概述
Snapshot 使用 Git 作为底层存储,在不影响工作目录的情况下创建代码快照。支持创建快照、计算差异、回滚和历史记录等功能。
定义位置
packages/opencode/src/snapshot/index.ts:78-195
主要对象
Patch
补丁信息,表示从某个快照到当前状态的变更。
| 属性名 | 类型 | 必填 | 说明 |
|---|---|---|---|
hash | string | 是 | 快照哈希 |
files | string[] | 是 | 变更的文件列表 |
FileDiff
文件差异详情,包含修改前后的完整内容。
| 属性名 | 类型 | 必填 | 说明 |
|---|---|---|---|
file | string | 是 | 文件路径 |
before | string | 是 | 修改前内容 |
after | string | 是 | 修改后内容 |
additions | number | 是 | 新增行数 |
deletions | number | 是 | 删除行数 |
TypeScript 类型定义
export type Patch = {
hash: string
files: string[]
}
export type FileDiff = {
file: string
before: string
after: string
additions: number
deletions: number
}
存储位置
快照存储在以下位置:
~/.opencode/data/snapshot/<project-id>/.git/
这使用的是独立的 Git 仓库,不影响项目的主 Git 仓库。
典型使用场景
1. 创建快照
// 跟踪当前工作目录并创建快照
const hash = await Snapshot.track()
console.log(hash) // Git tree hash,如 "a1b2c3d4..."
2. 获取补丁(变更文件列表)
const patch = await Snapshot.patch(hash)
console.log(`Changed files: ${patch.files.length}`)
console.log(`Files: ${patch.files.join(", ")}`)
3. 获取完整差异
const diff = await Snapshot.diff(hash)
console.log(diff) // Git diff 输出
4. 获取详细差异(FileDiff)
const diffs = await Snapshot.diffFull(fromHash, toHash)
for (const diff of diffs) {
console.log(`File: ${diff.file}`)
console.log(` Additions: ${diff.additions}`)
console.log(` Deletions: ${diff.deletions}`)
console.log(` Before length: ${diff.before.length}`)
console.log(` After length: ${diff.after.length}`)
}
5. 回滚到快照
// 将工作目录恢复到指定快照状态
await Snapshot.restore(snapshotHash)
6. 选择性回滚
// 回滚特定文件
const patches = [
{
hash: snapshotHash,
files: ["/path/to/file1.js", "/path/to/file2.ts"],
},
]
await Snapshot.revert(patches)
7. 清理旧快照
// 由调度器自动运行,修剪 7 天前的快照
await Snapshot.cleanup()
快照生命周期
工作流程
Session 中使用快照
存储配置
Git 配置
快照仓库使用以下 Git 配置:
git config core.autocrlf false
这确保跨平台的一致性。
修剪策略
默认修剪策略:
const prune = "7.days" // 修剪 7 天前的快照
由调度器每小时运行一次。
二进制文件处理
快照会检测并正确处理二进制文件:
// 从 git diff --numstat 中检测
const isBinaryFile = additions === "-" && deletions === "-"
if (isBinaryFile) {
// 不读取二进制文件内容
result.push({
file,
before: "",
after: "",
additions: 0,
deletions: 0,
})
}
性能考虑
快照创建
- 时间: O(n),其中 n 是变更的文件数
- 空间: 仅存储变更,不复制整个工作目录
差异计算
- 时间: O(m),其中 m 是变更的文件数
- 空间: FileDiff 存储完整文件内容
回滚操作
- 时间: O(k),其中 k 是要回滚的文件数
- 空间: 原地修改
错误处理
Git 失败
快照操作失败时记录警告但不会抛出异常:
const result = await $`git command`.quiet().nothrow()
if (result.exitCode !== 0) {
log.warn("operation failed", {
exitCode: result.exitCode,
stderr: result.stderr.toString(),
})
return defaultValue
}
变更历史
| 版本 | 变更内容 | 日期 |
|---|---|---|
| v1 | 初始 Snapshot 实现 | - |
| v1.1 | 添加 FileDiff 详细差异支持 | - |
| v1.2 | 添加二进制文件检测 | - |