bup restore 完全指南:从备份集中精确提取文件与目录
发布时间:2026/9/29 9:17:55来源:尧图网络
灾备CLI存储【免费下载链接】bupVery efficient backup system based on the git packfile format, providing fast incremental saves and global deduplication (among and within files, including virtual machine images). Please post problems or patches to the mailing list for discussion (see the end of the README below).项目地址https://gitcode.com/gh_mirrors/bu/bup点击查看免费下载bup restore是 bup 备份系统基于 git packfile 格式的增量备份工具中负责还原的核心命令它将由bup save创建的备份集backup set提取到本地文件系统。无论你是想恢复单个文件、整个目录树还是需要跨用户/跨主机地重映射属主、按正则排除路径、以稀疏文件节省磁盘本文都将结合 Documentation/bup-restore.1.md 的官方手册与 lib/bup/cmd/restore.py 的源码实现带你掌握bup restore的完整能力与底层行为。命令总览与路径语义语法与基本用法bup restore [-r host:[path]] [--outdiroutdir] [--exclude-rx pattern] [--exclude-rx-from filename] [-v] [-q] paths...bup restore从备份集中提取文件备份集由bup save详见 bup-save(1)创建。指定的paths具有统一的三段式结构/分支(branch)/版本(revision)/保存路径(some/where)路径成分含义branch要恢复的备份集名称对应bup save的--name-n选项revision备份集的版本。latest始终指向该分支最近一次备份用bup ls /branch可发现其他可用版本some/where之前保存的路径经过 strip/graft 处理后的路径例如etc/passwd从源码看restore.py 中的valid_restore_path()会先对路径做os.path.normpath归一化再校验其中是否包含分支与版本两个成分——不满足则报path %r doesnt include a branch and revision错误。若只传入/mybackup/latest/etc/passwd这样的完整路径代码通过vfs.resolve()在虚拟文件系统中逐级解析restore.py最终定位到具体的树对象treeish或文件对象。目录恢复的三种尾部语义some/where末尾写法的差异直接决定恢复结果落在哪里这是最容易用错也最实用的一处细节目录不带尾斜杠/branch/latest/etc恢复该目录本身其内容以子目录形式放入当前目录或--outdir下。即生成./etc/passwd。目录带尾斜杠/branch/latest/etc/只恢复该目录的子项直接铺到当前目录或--outdir不创建etc这层目录。即生成./passwd。目录尾带/./branch/latest/etc/.行为与带尾斜杠完全相同恢复子项到当前目录额外再把etc目录自身的元数据属主、权限、时间戳等应用到当前目录。对应地restore.py 中处理path_name b尾斜杠与path_name b./.两种特殊情况前者仅遍历子项逐个恢复后者在遍历之后再对b.调用apply_metadata()把源目录的元数据套用到目标目录上。latest符号链接特例若some/where恰好是名为latest的符号链接例如bup restore /foo/latestbup 会先解析出该链接指向的那次 save再恢复其内容而不是恢复latest 这个符号链接本身。源码中的处理位于 restore.py当解析结果长度恰为 3 且末级名为latest时改用vfs.resolve(src, blatest, parent...)跟随链接指向真实保存随后再把名字改回latest继续按常规流程恢复。元数据恢复与属主映射tar/rsync 风格语义只要元数据可用bup restore就会尽量恢复它。属主恢复遵循 tar/rsync 风格的语义理解这些规则是正确使用映射选项的前提名字优先通常优先使用用户名/组名而不是 uid/gid。root 限制除非以 root 运行否则不会尝试恢复属主user。回退当元数据中的用户名/组名在当前系统不存在时回退到数字 uid/gid。uid/gid 为 0作为特例uid 或 gid 为 0 时永不按名字重映射。系统限制某些系统不允许设置与已知用户/组不对应的 uid/gid此时 bup 会对每个相关路径记录错误。合成路径受bup save --graft影响的合成路径如根目录其组/其他人读执行权限按 umask 022 设定。元数据丢失路径因bup get --repair或早期 bup 版本丢失了元数据的路径详见 DESIGN 中的分类权限按 umask 077 保守设定。四条映射选项用于在应用上述规则之前调整可用的属主信息选项作用生效条件--map-user oldnew将保存的用户名old重映射为newnew为空字符串表示清除该用户无条件生效--map-group oldnew将保存的组名old重映射为newnew为空字符串表示清除该组无条件生效--map-uid oldnew将保存的 uidold重映射为new仅当路径没有有效用户名时才起作用--map-gid oldnew将保存的 gidold重映射为new仅当路径没有有效组名时才起作用关键推论由于名字优先规则只要路径带有有效用户名--map-uid/--map-gid就不生效。此时要么加--numeric-ids让数字 id 全面接管要么先用--map-user foo/--map-group foo清掉用户/组名。源码佐证parse_owner_mappings()restore.py对--map-uid/--map-gid使用^(-?[0-9])(-?[0-9])$解析允许负 id对--map-user/--map-group使用^([^])([^]*)$随后apply_metadata()restore.py依次对 user、group、uid、gid 四张映射表做替换最后调用meta.apply_to_path(name, restore_numeric_ids...)。测试 test/ext/test-restore-map-owner 用bup xstat逐一验证了user/group 重映射生效user/group 优先于 uid/gid仅映射 uid/gid 时结果不变清空 user/group 后 uid/gid 映射才生效以及uid/gid 为 0 优先于一切四组行为与手册描述完全吻合。硬链接Hardlink恢复bup restore会在可行时恢复硬链接但有两条限制不跨树链接不会链接到恢复树之外的目标。文件系统布局差异若恢复树与保存树的文件系统排布不同部分硬链接集合可能无法完整恢复。bup 会尽力按索引index时的硬链接集合形态重建即使 save 时集合中的文件已不再是硬链接但内容一致也会照索引时的关系重建。源码 restore.py 的hardlink_if_possible()维护一张hardlinks表记录每个硬链接目标的(restore_path, vfs_path, meta)三元组为每个新路径寻找已写入的兼容候选hardlink_compatible()restore.py要求 oid、mtime、ctime、mode 全部一致且same_file()判定为同一文件时才执行os.link()若返回EXDEV跨设备则放弃本次链接尝试。安全警告恢复树的权限可能过宽恢复过程中恢复树内数据的访问权限可能比原始源更宽松。除非确定安全无关紧要必须先恢复到私有子目录再将整棵树移动到最终位置示例见下文。这一建议源自手册 DESCRIPTION 的明确警示在自动化场景如按计划批量恢复中尤其重要。全部命令行选项详解选项说明-r, --remote[user]host:[path], --remoteURL从指定远程仓库恢复默认走 SSH细节见 bup(1) 的 REMOTE OPTIONS-C, --outdiroutdir在解包前创建并切换进目录outdir。源码中由mkdirp()创建后os.chdir()restore.py--numeric-ids恢复数字 IDuser/group 等而不是名字--exclude-rxpattern排除匹配pattern的路径pattern 为 Python 正则与以恢复树顶层为根的完整路径做非锚定匹配x/y会命中ox/yard或box/yards。想排除/tmp的内容但不排除目录本身用^/tmp/.可多次指定--exclude-rx-fromfilename从文件逐行读取--exclude-rx模式每行一条可重复指定完全空行会被忽略--sparse合理时以稀疏方式写出数据。合理当前即至少存在 512 个或更多连续零--map-user oldnew见上文元数据恢复与属主映射--map-group oldnew同上--map-uid oldnew同上--map-gid oldnew同上-v, --verbose提升日志输出。一次打印每个恢复的目录两次打印每个文件和目录-q, --quiet抑制输出含进度条。stderr 为 tty 时默认显示已恢复文件总数的进度条关于--exclude-rx的锚定语义手册特别强调恢复树的根匹配^/的顶层是正在恢复的归档树的顶层与文件系统目标无关。给定bup restore ... /foo/latest/etc/模式^/passwd$只有在文件当初被保存为/foo/latest/etc/passwd时才命中。--exclude-rx常用模式速查模式效果/foo$排除任何名为foo的文件/foo/$排除任何名为foo的目录/foo/.排除任何名为foo的目录的内容^/tmp/.排除根级tmp的内容排除模式的源码实现helpers.py 的parse_rx_excludes()遍历选项--exclude-rx直接re.compile()每个模式--exclude-rx-from逐行读取文件、rstrip(b\n)后忽略空行再编译任一模式非法都会经fatal()报错退出。匹配判定在should_rx_exclude_path()helpers.py对每个正则做rx.search(path)——非锚定search正是手册中x/y会命中ox/yard现象的来源。restore 端在 restore.py 以fullname目录追加/后缀与bup index --exclude-rx的路径约定保持一致调用该函数完成跳过。测试 test/ext/test-save-restore-excludes 覆盖了^/sub1/、/foo$、/foo/$、/foo/.四种模式及--exclude-rx-from空行忽略行为可直接照搬验证。--sparse的实现细节源码 restore.py 的write_file_content_sparsely()以0o600权限创建文件逐块调用 C 层write_sparsely(fd, buf, 512, trailing_zeros)见 lib/bup/_helpers.c跨块累计零字节计数最后用lseekftruncate截断尾部零区。C 实现会先探测至少 min_sparse_len512个连续零的区间把非稀疏段一次性写入、稀疏段跳过从而生成真正的稀疏文件。注意稀疏选项需要底层文件系统支持ext4 等测试 test/ext/test-sparse-files 会先用dev/sparse-size探测不支持稀疏的文件系统上测试会以 SKIP 跳过。实战示例0. 准备一份测试备份集$ bup index -u /etc $ bup save -n mybackup /etc/passwd /etc/profile1. 恢复单个文件$ bup restore /mybackup/latest/etc/passwd Restoring: 1, done. $ ls -l passwd -rw-r--r-- 1 apenwarr apenwarr 1478 2010-09-08 03:06 passwd测试 test/ext/test-restore-single-file 正是这个场景的自动化版本保存foo/baz后bup tick推进时间戳再bup restore -C restore foo/latest/$tmpdir/foo/baz最后用dev/compare-trees校验元数据与内容完全一致——证明单文件恢复不仅还原数据还还原了 mtime 等元数据。2. 目录恢复三种形态恢复etc目录本体到test/无尾斜杠$ bup restore -C test /mybackup/latest/etc Restoring: 3, done. $ find test test test/etc test/etc/passwd test/etc/profile只恢复etc的内容到test/尾斜杠$ bup restore -C test /mybackup/latest/etc/ Restoring: 2, done. $ find test test test/passwd test/profile恢复etc内容并把etc自身元数据套到test/上尾/.$ bup restore -C test /mybackup/latest/etc/. Restoring: 2, done. # 此时 test 与 etc 的元数据一致 $ find test test test/passwd test/profile3. 安全恢复整棵树私有子目录中转# mkdir --mode 0700 restore-tmp # bup restore -C restore-tmp /somebackup/latest/foo Restoring: 42, done. # mv restore-tmp/foo somewhere # rmdir restore-tmp先落到权限收紧的0700临时目录再整体搬移避免恢复过程中出现权限过宽的窗口期。4. 重映射用户与组# ls -l /original/y -rw-r----- 1 foo baz 3610 Nov 4 11:31 y # bup restore -C dest --map-user foobar --map-group bazbax /x/latest/y Restoring: 42, done. # ls -l dest/y -rw-r----- 1 bar bax 3610 Nov 4 11:31 y5. 重映射 uid必须先清除用户名否则 uid 不生效# ls -l /original/y -rw-r----- 1 foo baz 3610 Nov 4 11:31 y # ls -ln /original/y -rw-r----- 1 1000 1007 3610 Nov 4 11:31 y # bup restore -C dest --map-user foo --map-uid 10001042 /x/latest/y Restoring: 97, done. # ls -ln dest/y -rw-r----- 1 1042 1007 3610 Nov 4 11:31 y6. 用--numeric-ids的等价做法# bup restore -C dest --numeric-ids --map-uid 10001042 /x/latest/y Restoring: 97, done.与生态命令的关系bup restore是 bup 备份闭环中取回的一环与bup save写、bup ls查版本、bup ftp/bup fuse/bup web浏览与交互式取用共同构成完整工具链参见 bup(1)。远程恢复时通过-r指定仓库实际由 repo.py 中的repo_for_location()解析本地/SSH/URL 仓库后经虚拟文件系统 vfs.py 的resolve()、contents()、fopen()读取对象数据——理解这一点有助于排查路径解析失败权限不达预期等恢复问题。小结掌握bup restore的关键在于三点一是三段式路径与目录尾部的三种语义无斜杠 / 尾斜杠 //.它决定了恢复结果的落点二是属主恢复的 tar/rsync 语义与四条--map-*选项的生效优先级名字优先、uid/gid 需在无名字时或配合--numeric-ids才有效三是--exclude-rx以恢复树顶层为根的非锚定匹配规则。配合--sparse节省磁盘、-C指定输出目录、私有目录中转的安全实践即可在生产中精确、安全地完成任意粒度的数据恢复。赞分享灾备CLI存储【免费下载链接】bupVery efficient backup system based on the git packfile format, providing fast incremental saves and global deduplication (among and within files, including virtual machine images). Please post problems or patches to the mailing list for discussion (see the end of the README below).项目地址https://gitcode.com/gh_mirrors/bu/bup点击查看免费下载相关推荐bup cat-file 深度指南从 bup 归档中低层提取文件内容、元数据与 .bupm 目录清单bup cat file 深度指南从 bup 归档中低层提取文件内容、元数据与 .bupm 目录清单 bup cat file 是 bup 备份套件中的一个低灾备CLI存储bup ls 命令详解浏览 bup 备份仓库目录结构的完整指南bup ls 命令详解浏览 bup 备份仓库目录结构的完整指南 bup 是一款基于 git packfile 格式的高效备份系统支持快速增量保存与全局去重灾备CLI存储bup meta 完全指南备份系统元数据归档的创建、提取与编辑实战bup meta 完全指南备份系统元数据归档的创建、提取与编辑实战 导读 bup meta 是 bup 备份套件中专门用于 创建、提取与编辑元数据归档 的命令灾备CLI存储创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网