☰
Gentle-AI 备份与回滚指南:快照、去重、保留策略与恢复实操
2026/9/29 2:28:17 网站建设 项目流程

【免费下载链接】gentle-ai

Gentle-AI configures the AI coding agents you already use: Claude Code, Cursor, OpenCode, Codex, Pi, and more. Choose persistent memory, Organic-Driven Development, curated skills, MCP servers, personas, and optional bounded review. Open source, no agent lock-in.

项目地址:https://gitcode.com/gh_mirrors/ge/gentle-ai
点击查看免费下载

Gentle-AI 会在每次install、sync、upgrade操作前自动为你的 AI 编码 Agent(Claude Code、Cursor、OpenCode、Codex、Pi 等)配置文件创建快照备份,并采用压缩、去重与自动修剪策略控制磁盘占用。本文围绕官方 备份与回滚指南 展开,结合仓库内internal/backup/包的源码实现,完整讲解备份触发流程、快照结构与清单字段、保留与去重算法、TUI 与 CLI 的恢复操作,以及验证失败后的标准处置路径,帮助你安全、可预期地管理配置文件回滚。

备份系统如何工作

备份系统在每次运行gentle-ai install、sync或upgrade时自动触发,核心流程分为四步,对应 snapshot.go 中Snapshotter.Create的实现:

  1. 计算校验和(checksum):对所有将要备份的文件计算复合 SHA-256 校验和;
  2. 去重跳过(dedup):如果结果与最近一次备份完全相同,则跳过本次备份,不产生新的快照;
  3. 创建压缩快照:将所有配置文件打包为snapshot.tar.gz;
  4. 修剪旧备份:仅保留最近 5 个未钉住(unpinned)的备份,删除其余部分。

触发点与元数据来源

  • install/sync 路径在 run.go 的prepareBackupStep中执行:先通过ComputeChecksum做去重判断,再调用snapshotter.Create创建快照,随后将source、description、created_by_version等元数据写入manifest.json,最后执行保留期修剪(backup.Prune)。
  • upgrade 路径在 executor.go 中通过snapshotCreator变量(默认为backup.NewSnapshotter().Create)在升级执行前创建快照;ExecuteOptions.SkipBackup对应 CLI 的--no-backup,可对单次运行显式跳过备份创建与修剪。
  • 每次 install/sync 还会在临时目录创建一份"事务快照"(transaction snapshot),供安装过程中失败时即时回滚使用,成功后随清理步骤删除(见 run.go 的cleanupRollbackSnapshot)。

校验和算法细节

retention.go 中ComputeChecksum的算法是:过滤出存在且为普通文件的路径 → 按字典序排序保证确定性 → 对每个文件内容计算 SHA-256 → 拼接所有path:hexhash\n对 → 对拼接结果再做一次 SHA-256 得到复合摘要。校验和包含绝对路径,因此去重是"每台机器"级别的,不同主机的相同文件会产生不同校验和——这是有意设计。当没有任何文件时,使用空字符串的 SHA-256 作为稳定哨兵值(emptyFilesChecksum),使连续两次零文件备份也能被正确识别为重复(snapshot.go)。

快照内容与目录结构

每个备份快照存放在~/.gentle-ai/backups/<id>/下(目录解析见 manifest.go),包含两个关键文件:

  • manifest.json—— 元数据清单:来源(source)、时间戳(created_at)、文件数(file_count)、校验和(checksum)、钉住状态(pinned)等;
  • snapshot.tar.gz—— 所有被备份文件的压缩归档。

对于操作前不存在的路径,清单记录existed=false,以便回滚时正确"反向删除"安装过程中创建的文件。

manifest.json 字段说明

manifest.go 定义的Manifest结构主要字段如下:

字段JSON 键含义
IDid备份目录名(基于时间戳生成)
CreatedAtcreated_atUTC 创建时间
RootDirroot_dir备份目录绝对路径
Sourcesource来源:install/sync/upgrade/uninstall(旧清单缺省显示unknown source)
Descriptiondescription人工可读的描述(TUI 中r键可编辑)
FileCountfile_count实际存在并被快照的文件数(existed=false的条目不计入)
CreatedByVersioncreated_by_version创建该备份的 gentle-ai 版本
Pinnedpinned是否被钉住(受保护不被修剪)
Compressedcompressed是否使用 tar.gz 压缩归档
Checksumchecksum复合 SHA-256,用于去重
Entriesentries每个备份目标的明细条目

DisplayLabel方法(manifest.go)组合来源、本地时间戳与文件数生成人类可读标签,钉住的备份会带[pinned]前缀——这正是 TUI 与gentle-ai restore --list列表里每行显示的内容。

备份范围(重要边界)

备份范围:升级前与同步前的快照只覆盖state.InstalledAgents(~/.gentle-ai/state.json)中列出的 Agent。通过 gentle-ai 之外方式安装的 Agent 配置目录不会进入快照。

此外,upgrade 的备份遍历通过backupExcludeSubdirs白名单跳过运行态/缓存类目录(executor.go),例如:backups(绝不递归进备份自身)、cache、debug、downloads、plugins(MCP 插件二进制可达 60+ MB)、sessions、tasks、telemetry、node_modules,以及 Claude Code 的projects(单目录可超 1 GB)、Gemini/Antigravity 的browser_recordings(可达 3+ GB)等。这些目录不是配置、且体积巨大,跳过它们能避免升级过程被拖垮。

保留策略与去重

设置项默认值行为
保留数量(Keep count)5保留最近 5 个未钉住的备份
钉住备份(Pinned)永不删除无论数量多少都免于修剪
重复备份(Duplicates)跳过配置未变化时不创建新备份
压缩(Compression)始终启用新备份使用 tar.gz(体积约缩小 75%)

默认保留数量5定义在 retention.go 的DefaultRetentionCount。修剪逻辑Prune(retention.go):

  1. 读取backupDir下所有含可读manifest.json的子目录;
  2. 按CreatedAt从新到旧排序;
  3. 划分出未钉住的部分,若数量超过保留上限,则删除最旧的超额备份;
  4. 单个目录删除失败仅记录日志、不中断其余备份的评估;
  5. 无manifest.json的目录被静默跳过,不计入限额。

去重由DuplicateManifest(retention.go)实现:只有当最近一次备份的Checksum与本次相同且校验和不为空时才判定为重复。prepareBackupStep在判定重复时还会通过manifestTargetsMatch确认目标路径集合完全一致(run.go),双重保险后才真正跳过快照创建。

钉住备份(Pinning)

任何备份都可以在 TUI 中标记为"钉住"以保护其不被自动修剪:

  1. 运行gentle-ai,进入Backups屏幕;
  2. 使用j/k选择备份;
  3. 按p切换钉住/取消钉住;
  4. 钉住的备份显示[pinned]标识。

钉住的备份永远不会被自动删除,即使超过保留数量上限也不例外。底层由TogglePin实现(manifest.go):翻转清单的Pinned字段并重写manifest.json;TUI 的按键处理在 model.go,Prune在分区时完全跳过Pinned == true的备份(retention.go)。

通过 TUI 管理备份

进入Backups屏幕后,可用快捷键如下(TUI 按键分发见 model.go):

按键操作
j/k上下移动选择
Enter恢复选中的备份
p钉住/取消钉住(保护免于修剪)
r重命名(添加描述)
d删除
Esc返回

r键调用RenameBackup(manifest.go),只更新清单中的Description字段而不重命名目录;d键先进入删除确认屏幕,再调用DeleteBackup(manifest.go)删除整个备份目录。

通过 CLI 恢复备份

gentle-ai restore是独立的命令行恢复入口,完整实现见 restore.go:

gentle-ai restore [--list | latest | <id>] [--yes]
参数作用
--list列出所有可用备份而不执行恢复
latest恢复最新备份(列表中第一个)
<id>按 ID 精确恢复指定备份
--yes/-y跳过确认提示(适合脚本/非交互场景)

典型用法

# 查看可用备份 gentle-ai restore --list # 恢复最近一次备份 gentle-ai restore latest # 按 ID 恢复,并跳过确认 gentle-ai restore 20260928150405.000000000 --yes # 恢复过程中提示确认(默认交互) gentle-ai restore latest # Restore backup <id> (install — 2026-09-28 15:04)? # This will overwrite your current configuration. Type 'yes' to confirm:

列表输出格式为[序号] ID 标签 [版本],例如[1] 20260928150405.000000000 install — 2026-09-28 15:04 (5 files) [v3.x]。确认逻辑只接受yes(忽略大小写),EOF 或非确认输入均视为拒绝并提示使用--yes(restore.go)。

恢复行为细节

  • existed=true:从快照将文件恢复到原始路径;
  • existed=false:删除该文件(回滚安装期间创建的文件);
  • 按文件原子写入,不存在部分恢复状态;
  • 同时兼容压缩(tar.gz)与旧版(plain file)备份。

原子写入与类型安全

restoreEntry(restore.go)通过filemerge.WriteFileAtomicMode写入文件并恢复原始权限位(mode)。恢复前会对清单中的每条OriginalPath做严格的路径围栏校验(isPathUnderRoot):路径必须是绝对路径、且位于允许的根目录(默认$HOME)之下;对于压缩备份的SnapshotPath还要求是相对路径(绝对路径会读取活文件系统而非解压目录,直接拒绝)。解压归档时,compression.go 会拒绝任何含..的条目、解析到目标目录本身的"."条目,以及非普通文件类型,防止路径穿越攻击。

PathKind 分类语义

清单条目的Kind字段(manifest.go)决定恢复策略:

  • regular:普通文件,进入归档并在恢复时写回;existed=false时显式删除;
  • directory:空目录,不归档,恢复时确保目录存在、绝不删除预先存在的目录;
  • symlink_directory:指向目录的相对符号链接,不归档,恢复时校验LinkTarget是安全相对路径(非绝对路径、解析后仍在根目录内,防..与..\穿越)后再重建;若磁盘上已存在同路径节点,则必须仍是符号链接且指向相同目标,否则 fail-closed 拒绝(restore.go);
  • ""(unknown,旧版清单):恢复时采用保守策略——existed=false的 unknown 条目只保留不删除,因为无法证明该路径是安装创建的,删除可能误伤用户自有文件(restore.go)。

旧版备份兼容

v1.16 之前的旧版备份使用files/目录存放普通文件副本,而非 tar.gz 归档(Compressed=false)。RestoreService.Restore会根据manifest.Compressed自动分流到restoreCompressed或restorePlain(restore.go),两种格式均可完整恢复。旧版清单没有Source、FileCount等字段时,显示层优雅降级为unknown source、不显示文件数。

验证失败后的标准处置

如果安装后的验证失败,按照文档给出的四步走:

  1. 审查验证报告中的失败检查项(报告格式由 report.go 渲染,逐项显示[ok]/[!!]/[??]/[--]状态与失败原因,汇总行形如Verification checks: N passed, N failed, N warnings, N skipped);
  2. 通过 TUI 或gentle-ai restore latest从最新快照恢复;
  3. 使用--dry-run重新运行安装以验证计划(install、sync、upgrade均支持 dry-run,不产生任何文件变更);
  4. 修复外部依赖后重新安装。

恢复操作全程有防误伤护栏:清单中的root_dir必须位于~/.gentle-ai/backups/之下才会执行删除(DeleteBackup的isRootDirUnderBackupRoot检查,manifest.go);回滚时rollbackRoots(run.go)以本次 install/sync 实际写入过的 home 目录、工作区目录为边界校验每个条目,防止被篡改的清单将文件写到任意位置。

rollback 不覆盖的内容

  • 通过brew install、apt-get install或pacman -S安装的软件包不会在回滚时被卸载——快照系统只处理配置文件;
  • 需要撤销包安装时,请直接使用平台包管理器,例如brew uninstall、sudo apt-get remove、sudo pacman -R。

这也决定了备份系统的定位:它是配置层的安全网,负责把 Agent 配置文件恢复到操作前状态;系统级依赖属于包管理器职责范围,两者互补而不混淆。

总结

Gentle-AI 的备份与回滚机制在 internal/backup 包中形成了一条完整链路:Snapshotter.Create负责快照与元数据记录 →ComputeChecksum/DuplicateManifest实现内容去重 →Prune按保留策略修剪 →RestoreService按 PathKind 语义安全恢复。日常使用中,你只需记住三件事:所有install/sync/upgrade都会自动留后路;重要备份用 TUI 的p钉住;出问题时用gentle-ai restore latest一键回退,再用--dry-run验证计划后重装。

【免费下载链接】gentle-ai

Gentle-AI configures the AI coding agents you already use: Claude Code, Cursor, OpenCode, Codex, Pi, and more. Choose persistent memory, Organic-Driven Development, curated skills, MCP servers, personas, and optional bounded review. Open source, no agent lock-in.

项目地址:https://gitcode.com/gh_mirrors/ge/gentle-ai
点击查看免费下载
上一篇:紧急修复:Librosa MFCC参数传递陷阱及0.11.0版本适配指南
下一篇:彻底解决Caddy证书冲突:忽略已加载证书的终极配置指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询