与修复(repair)实战详解)
灾备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 仓库中的官方手册 Documentation/bup-get.1.md 为骨架完整讲解bup get命令——一个用于把源仓库中的引用branch、save、tag 等按指定方式拷贝到目标仓库并可选择进行数据重写--rewrite与已知损坏修复--repair的核心工具。你将掌握全部七类传输方法--ff/--append/--pick/--force-pick/--new-tag/--replace/--unnamed、全部选项语义、上下文选项contextual options的用法、修复能力清单以及远程推送/拉取-r与bup on HOST get ...的完整实战命令。一、bup get是什么在仓库之间搬运 git 对象bup是一个基于 git packfile 格式的高效备份系统。bup get负责把源仓库中的引用ref即分支、save、tag 等传输到目标仓库默认遵循--bup-dir与BUP_DIR环境变量指定的仓库位置传输行为由命令行指定的 METHOD 决定。默认情况下bup get会原样--copy数据而不做任何改动但它也可以--rewrite数据按目标仓库的分割配置重新切分可能改变去重粒度以及--repair某些已知类型的损坏。源实现位于 lib/bup/cmd/get.py命令整体流程为解析参数 → 解析源引用 → 解析/校验目标 → 创建 Rewriter仅当需要重写时→ 逐个执行传输处理器 → 最后统一更新引用指针。1.1 基本语法SYNOPSISbup get [-s source-path] [-r host:path] OPTIONS (METHOD ref [dest])...ref源仓库中要取出的对象引用dest可选的目标仓库引用只有 METHOD 名称以冒号结尾时才能指定dest即--ff:、--append:、--pick:、--force-pick:、--new-tag:、--replace:这六种形式。基本示例bup get -s /source/repo --ff foo bup get -s /source/repo --ff: foo/latest bar bup get -s /source/repo --pick: foo/2010-10-10-101010 bar bup get -s /source/repo --pick: foo/2010-10-10-101010 .tag/bar1.2 引用类型与 latest 特例某个 METHOD 的具体行为取决于ref与dest的类型——分支branch、save、tag 等。这里 save 是 bup 对一次备份快照的称呼对应 VFS 中一个分支下的某个YYYY-MM-DD-HHMMSS形式的提交。一个值得注意的特例如果ref指向 latest save 符号链接则 bup 会完全按照该 latest 所指向的那个 save 来处理而不是把 latest 符号链接本身作为对象。也就是说bup get foo/latest # 实际等价于类似 bup get foo/2013-01-01-030405从源码看find_vfs_item() 在解析到vfs.FakeLink即 latest时会顺着leaf_item.target继续解析到底层的vfs.Commit并把结果归类为save这正是文档所述行为的实现依据。1.3 快进判定、tag 覆盖规则与新提交的元数据某些场景下bup get会按 是否是一次快进fast-forward 来评估分支操作快进要求目标分支的现有提交必须是源提交的祖先。在 handle_ff() 中若目标提交不在源提交的rev_list中会直接报错destination is not an ancestor of source。已存在的目标 tag只能被--replace或--force-pick覆盖。当创建新提交时如--append、--pick等提交的author、author 日期与 message 沿用原提交但committer 与 committer 日期使用当前用户与当前时间。对应实现见 transfer_commit()它读取源提交的author_name/author_mail/author_sec/author_offset/message却用userfullname()/username()/hostname()和当前time.time()生成新的 committer 信息。配合相应选项bup 会为每个被更新的目标引用打印 commit、tree 或 tag 哈希当两者都相关时tree 哈希先于 commit 哈希打印见 log_item()。1.4 本地与远程本地引用可以通过--remote选项推送到远程仓库远程引用可以通过bup on HOST get ...拉取到本地仓库。详见 Documentation/bup-on.1.md 与下文 EXAMPLES。1.5 重要警告CAUTION这是 bup 中少数几个可能以有意的破坏性方式修改归档的命令。但文档也给出一个朴素的验证法如果你在运行该命令后仍然能成功 join 或 restore 你在意的数据那就是一个相当积极的信号说明操作是正确的。源码树中的dev/compare-trees脚本可用于对比操作前后的结果dev/compare-trees。二、七类传输方法METHODS详解方法参数行为--ffref将dest快进到与ref一致。未指定dest时若ref是 save则dest取该 save 所属分支若ref是分支或 tag则dest使用同名。--ff:ref dest同上但显式指定目标。--appendref将ref代表的全部提交追加到dest上成为新提交。若ref是目录/tree则为该 tree 追加一个新提交。未指定dest时若ref是 save 或分支则dest取ref的分支名若ref是 tag则使用同名。--append:ref dest同上但显式指定目标。--pickref将ref命名的单个提交追加到dest上成为新提交。未指定dest时若ref是 save则dest取该分支名若ref是 tag则使用同名。--pick:ref dest同上但显式指定目标。--force-pick/--force-pick:ref [dest]与--pick相同但不拒绝覆盖已存在的 tag且若该 tag 指向某个提交会将其作为ref的父提交。--new-tag/--new-tag:ref [dest]为ref创建desttag但拒绝覆盖已存在的 tag。未指定dest且ref是 tag 时使用同名。--replace/--replace:ref [dest]用ref覆盖clobberdest可覆盖任何已存在 tag或替换任何已存在分支。未指定dest且ref是分支或 tag 时使用同名。--unnamedref把ref以无名称方式拷入目标仓库除非该对象日后通过其他方式被引用参见bup tag否则会留下一个潜在悬空引用。目前仅兼容--copy。几点源码级佐证--ff的树型拒绝resolve_ff() 明确拒绝源为 tree--ff一个目录是无意义的只能--appendtree 到分支并要求源必须是 branch/save/commit 之一。--append支持 treehandle_append() 对 tree 型源会生成一条消息为bup get的提交以该 tree 作为新提交内容、现有dest分支头作为父提交。--pick只接受单个提交resolve_pick() 限定源类型为 commit 或 save不能是整条分支handle_pick() 中若目标是一个 committish分支/commit/save则把它作为新提交的父提交若目标是 tag 或不存在则直接以无父方式创建。tag 覆盖保护--pick遇到已存在 tag 会报错需--force-pick--new-tag遇到已存在 tag 也会报错需--replace--replace对 tag 直接覆盖、对分支直接替换。这些检查分别位于resolve_pick、resolve_new_tag、resolve_replace中。--unnamed的 git: 引用resolve_unnamed() 允许git:前缀的引用如git:hash这是 0.33.5 发布说明中恢复缺失对象工作流的基础。三、全部选项OPTIONS详解选项说明-s path/-S url/--source path/--source-url url用path或url作为源仓库替代默认值。仓库 URL 语法参见bup(1) 的 REPOSITORY URLS 章节。-r [user]host:[path]/--remote.../--remoteURL将ref写入指定远程仓库默认经 SSH。参见bup(1) 的 REMOTE OPTIONS 章节。-c, --print-commits为每个被更新的分支打印新的 git commit id。-t, --print-trees为每个被更新的分支打印文件系统根的 git tree id。--print-tags为每个被更新的 tag 打印新的 git id。--copy原样拷贝数据不做重写或修复。默认行为。--rewrite按目标仓库的配置重写数据例如其bup.split.files与bup.split.trees配置值。传输过程中还可能执行一些附带修复见 REPAIRS 一节。当源与目标仓库配置在相关维度上有差异时必须显式指定--rewrite、--repair或--copy之一目前--rewrite仅支持 save 的 append 与 pick尚不支持 tree 等。注意重写一个 git 创建的 save 会而且目前一定会引入 bup 相关的改动此外虽然经过测试--rewrite相对较新需要比bup get本身更加谨慎见 CAUTION建议仔细验证结果。该选项是上下文选项contextual。--repair在--rewrite所做的基础上在传输过程中执行全部已知修复。见 REPAIRS 一节。上下文选项。--repair-id ID设置修复会话标识符默认是一个 UUIDv4。该标识符会出现在传输期间所做的任何修复中。当前该标识符必须为 ASCII且不得包含控制字符或 DEL即字节值须 ≥ 20 且 127。上下文选项。--ignore-missing忽略传输中遇到的缺失对象。目前仅--unnamed支持且潜在危险。--exclude-rxpattern排除任何匹配pattern的路径。pattern 必须是 Python 正则表达式。该 pattern 会与完整路径做非锚定比较所以x/y能匹配ox/yard或box/yards。若想排除/tmp的内容但不排除目录本身用^/tmp/.。可重复指定。仅重写或修复时支持。上下文选项。--exclude-rx-fromfilename从filename读取--exclude-rxpattern每行一个可重复指定。完全空行会被忽略。仅重写时支持。上下文选项。--no-excludes忘掉此前所有--exclude-rx/--exclude-rx-from选项。上下文选项。-v, --verbose增加输出详细度可多次使用。-v打印每个被取回条目的名称-vv增加目录名-vvv增加每个文件名。--bwlimitbytes/sec每秒向服务器传输不超过bytes/sec字节避免占满网络带宽。可用后缀 k、M、G 表示 1024、1024*1024、1024*1024*1024 的倍数。实现中通过client.bwlimit opt.bwlimit生效lib/bup/cmd/get.py。-#, --compress#设置压缩级别 #0–99 最高0 不压缩。默认取配置的pack.compression或core.compression否则为 1快速、宽松压缩。3.1--exclude-rx的路径匹配示例来自官方文档/foo$—— 排除任何名为 foo 的文件/foo/$—— 排除任何名为 foo 的目录/foo/.—— 排除任何名为 foo 的目录的内容^/tmp/.—— 排除根级 tmp 的内容在解析上--exclude-rx与--exclude-rx-from会被收集后经parse_rx_excludes()编译为正则列表lib/bup/cmd/get.py并且只有在模式为--rewrite/--repair时才允许使用否则直接报错。四、上下文选项CONTEXTUAL OPTIONS同一命令内为不同 METHOD 设置不同模式部分选项如--repair、--ignore-missing、--exclude-rx可以因 METHOD 而异——每个选项都会改变下一个 METHOD 的上下文。例如bup get ... --ignore-missing --unnamed REF \ --no-ignore-missing --rewrite --append REF如果省略--no-ignore-missing该命令会失败因为--ignore-missing与--rewrite不兼容。实现上parse_args() 用pending_method_context记录每个 METHOD 生效前的上下文参数每遇到一个新的 METHOD 才固化出对应的Specmake_spec() 中会检查--ignore-missing与--repair/--rewrite互斥且只允许--unnamed--exclude-rx只允许 rewrite/repairrewrite/repair 模式只允许 append/pick/force-pick 方法。性能提示更改当前生效的 excludes 代价较高因为只要某个 METHOD 的 excludes 与上一个 METHOD 不同就必须清空已记忆重写的缓存rewriter 数据库所以不要频繁切换 excludes。测试 test/ext/test-get-excludes 正好验证了这种上下文性它在一个bup get命令里依次用--exclude-rx t.*、--no-excludes、--exclude-rx one对同一 save 做三次--pick得到三个不同的ls结果还验证了被忽略的上下文参数如--exclude-rx y --ignore-missing置于末尾会报trailing arguments with no effect错误。五、REPAIRS--repair能修复什么bup get在请求--repair时可以在传输过程中修复或缓解若干已知问题--rewrite期间也可能执行一部分附带修复不改变结果功能的修复。5.1 修复 1被删减的.bupm元数据条目背景0.25 至 0.30.1不含之间的 bup 版本可能极少见地丢失非目录的元数据条目可用bup-validate-refs(1) --bupm检测。这会使得同一目录下所有其他非目录路径的元数据变得不可用歧义。修复行为当检测到这种被删减的.bupm时--repair会丢弃除目录自身 . 条目之外的所有.bupm条目因此受影响的路径会丢失大部分或全部元数据属主、权限、时间戳等。这些路径在通过bup-restore(1)、bup-ls(1)等展示时将具有受限权限如同 umask 077 的结果。测试佐证test/ext/test-get-repair-bupm 构造了一个被删减的 .bupm仓库先用bup save生成两个根文件与三个根文件的两次快照再把三文件快照的.bupm替换成两文件快照的旧的、条目更少的.bupm制造bup validate-refs --bupm能检测出的abridged-bupm情形。随后验证普通--rewrite --append会拒绝该损坏退出码 2而--repair --append以退出码 3 成功并打印repairs needed, repair-id: ...恢复出的文件mode: 100600 (-rw-------)、rdev: 0、mtime: 0与文档umask 077 般的受限权限完全一致。5.2 修复 2缺失对象missing objects→ 合成修复文件背景使用 0.33.5 之前的bup get或bup gc可能导致仓库出现缺失对象可用bup-validate-object-links(1)检测。详见发布说明 note/0.33.5-from-0.33.4.md这些命令可能创建不完整的 tree 或 commit例如bup save或bup get可能产生数据缺失的快照如果你从未用过bup gc或bup get仓库基本不可能受影响。检测方法是运行bup-validate-object-links(1)若报告no HASH for PARENT_HASH形式的断链则先bup gc --ignore-missing收尾修复前可尝试从其他仓库找回缺失对象见下文恢复缺失对象流程。修复行为为修复受影响的 tree--repair会为任何含有缺失对象的路径替换为合成的 repair files。注意目前不支持取回分割文件split files的未受影响部分——整个文件会被一个 repair 文件替换。这些 repair 文件包含--repair-id以及替换的相关信息。由于分割树split trees的支持是在该问题修复之后才加入的因此应该不受影响。测试佐证test/ext/test-get-missing 用dev/perforate-repo --drop-oids人为删掉对象制造缺失场景验证不带--ignore-missing的--unnamed传输会因MissingObject失败带--ignore-missing的--unnamed会打印skipping missing source object ...并继续同一命令中先--ignore-missing --unnamed再--no-ignore-missing --unnamed能分别按各自上下文处理。5.3 附带修复Incidental repairs还可能执行不会从功能上改变结果的附带修复。例如bup 会在两个地方记录符号链接目标但一般只引用其中一处如果另一处缺失bup 可以从第一处恢复它。测试佐证test/ext/test-get-repair-symlinks 验证了三种符号链接损坏场景有元数据但 blob 缺失的符号链接--rewrite与--repair都能附带修复提交消息中带Bup-Restored-Link-Blob: oid 2元数据与 blob 指向不一致的符号链接--rewrite会报Symlink with mismatched targets (can --repair)而失败退出码 2--repair则成功修复并在提交消息中记录Bup-Fixed-Link-Blob: was not-1 for 2退出码 3完全缺失无元数据的符号链接--copy/--rewrite失败--repair用 repair blob 替换并在提交消息中记录Bup-Replaced: oid 2。5.4 修复的审计记录发生修复时bup 会在新提交消息中写入 trailer包括Bup-Version、Bup-Argv、Bup-Repair-ID、Bup-Repaired-Save、Bup-Lost-Meta等见 test/ext/test-get-repair-bupm 的 trailer 校验。传输结束时若发生了修复且无其他错误会打印提示可在git --git-dir REPO log ...中搜索Repair-ID:找到相关记录lib/bup/cmd/get.py。5.5 用--unnamed --ignore-missing恢复缺失对象0.33.5 工作流发布说明 note/0.33.5-from-0.33.4.md 给出了完整流程先收集缺失对象清单再批量取回bup validate-object-links | tee validate-out grep -E ^no validate-out | cut -d -f 2 | sort -u missing-objects sed -e s/^/--unnamed git:/ missing-objects unnamed-objects xargs bup get --source repo --unnamed --ignore-missing unnamed-objects # 或 xargs bup on HOST get --unnamed --ignore-missing unnamed-objects若缺失对象太多导致 xargs 参数过长可指定偶数xargs -n 64等。之后运行bup validate-object-links确认断链是否修复。另可用bup validate-ref-links SAVE...高效校验某次快照。六、EXAMPLES官方完整实战示例以下示例完整引自官方文档并附注解读# 1. 把 src-repo 中的 archives 分支更新或拷贝到本地仓库。 $ bup get -s src-repo --ff archives # 2. 把某次 archives 快照追加到 pruned-archives 分支。 $ bup get -s src-repo --pick: archives/2013-01-01-030405 pruned-archives # 3. 在远程主机上执行把 remotehost 的 archives 分支更新/拷贝到本地仓库。 $ bup on remotehost get --ff archives # 4. 把本地 archives 分支更新/拷贝到 remotehost。 $ bup get -r remotehost: --ff archives # 5. 把 src-repo 的 archives 分支更新/拷贝到 remotehost源、目标都是远程/其他。 $ bup get -s src-repo -r remotehost: --ff archives # 6. 让 remotehost 上的 archives-2 分支匹配 archives。 # 若 archives-2 已存在且不是 archives 的祖先bup 会拒绝。 $ bup get -r remotehost: --ff: archives archives-2 # 7. 用 x 的内容替换分支 y。 $ bup get --replace: x y # 8. 把本地 archives 分支的最新快照拷贝为远程 tag foo。 $ bup get -r remotehost: --pick: archives/latest .tag/foo # 9. 若 foo 已存在改用 force-pick。 $ bup get -r remotehost: --force-pick: archives/latest .tag/foo # 10. 把上面的 foo 追加到本地 other-archives 分支。 $ bup on remotehost get --append: .tag/foo other-archives # 11. 只取 archives/latest 中的 /home 目录追加到 only-home 分支。 $ bup get -s $BUP_DIR --append: archives/latest/home only-home # 12. 对 archives 分支做重新分割rewrite。 # 注意一次性全量执行可能需要额外空间最大约等于该分支的大小 # pick 方法可以更选择性地/增量地完成重写。 # 假设 BUP_DIR 原本没有 split 配置。 # $ git --git-dir $BUP_DIR config bup.split.trees true $ git --git-dir $BUP_DIR config bup.split.files legacy:16 $ bup get --rewrite --append: archives archives-resplit # # 检查 archives-resplit 是否正常例如试 restore、join 等见 CAUTION # 确认满意后可再执行 # $ bup rm archives $ bup gc $ git --git-dir $BUP_DIR branch -m archives-resplit archives # # 13. 修复某次单独的 save。 $ bup get --repair --pick archives/latest fixed # # 检查 fixed/latest 是否正常例如试 restore、join 等见 CAUTION。示例 12 展示了一个典型的重新分割场景通过 git config 修改bup.split.trees与bup.split.files然后用--rewrite --append把整个分支按新配置重写到一个新分支验证通过后再用bup rmbup gc清掉旧分支并重命名。实现中bup get会读取源/目标仓库的hashsplit.configurationsrc_split_cfg与dest_split_cfg当两者不一致而又未显式声明模式时会直接报错要求给出--[no-]rewritelib/bup/cmd/get.py——这正是配置不同必须显式指定模式这一规则的实现来源。七、退出状态EXIT STATUS退出状态0正常完成无错误。退出状态3表示需要修复且修复成功并且没有发生其他错误lib/bup/cmd/get.py 返回EXIT_RECOVERED。其余非零状态参数/用法错误或传输失败如源对象缺失、目标非祖先、覆盖已有 tag 被拒等。测试中可以看到--repair成功常伴随退出码 3被拒绝的操作通常为 2。八、源码级实现原理一次bup get的完整旅程在 lib/bup/cmd/get.py 中可以清晰看到与文档描述一一对应的实现结构参数解析parse_args把命令行拆成若干个Specmethod / src / dest / ignore_missing / repair_info / excludes / rewriter每个 METHOD 带自己的上下文--[no-]ignore-missing、--repair-id、--exclude-rx等选项在 METHOD 之间独立生效。引用解析resolve_targets先对每个 spec 调用对应的resolve_ff/resolve_append/resolve_pick/resolve_new_tag/resolve_replace/resolve_unnamed把源src_repo的 VFS 或git:对象与目标解析为Target。这个阶段就完成了文档所述的全部合法性校验如 tag 覆盖保护、源类型限制、dest 推导规则并且在写入任何数据之前就执行完所有校验保证明显错误的情形在动手前即失败。创建 Rewriter仅当有 spec 需要重写--rewrite/--repair时创建Rewriter(split_cfgdest_split_cfg)以目标仓库的分割配置为准。执行传输handlers按方法分派到handle_ff/handle_append/handle_pick/handle_new_tag/handle_replace/handle_unnamed。对象级传输统一由get_random_item()完成——它用walk_object()从源仓库深度优先遍历对象图stop_atalready_seen利用目标仓库已有的对象做去重截断这正是 bup 全局去重在传输侧的体现然后把对象just_write()写入目标对远程目标仓库还特别处理了服务器建议导致索引缓存变化的边界情况避免重复写入引发sync_index()异常。最后统一更新引用所有对象写入完成后才把updated_refs中的引用指针一次性update_ref到新值——如果中途出错旧引用保持不动这是文档 CAUTION 背后要么全部成功、要么不动旧引用的原子性设计。verbose / 打印log_item()按-c/-t/--print-tags/-v输出 commit、tree、tag 哈希与条目名称。8.1 相关测试清单可在仓库中自行复现验证测试脚本覆盖点test/ext/test-get-excludes--rewrite --exclude-rx、--no-excludes、上下文切换、无效上下文参数报错test/ext/test-get-missing--unnamed git:引用、--ignore-missing开关、多 spec 混合上下文test/ext/test-get-repair-bupm被删减.bupm的检测、--repair修复、restore 后的受限权限、提交 trailer 审计test/ext/test-get-repair-symlinks符号链接三类损坏blob 缺失附带修复、目标不一致rewrite 拒绝/repair 修复、完全缺失repair 替换test/ext/test-get-rewrite-missingrewrite 过程中的缺失对象处理九、适用前提与注意事项bup get是破坏性命令之一执行前务必用dev/compare-trees或试 restore/join 验证结果dev/compare-trees。源与目标仓库的分割配置bup.split.files/bup.split.trees不同时必须显式声明--copy/--rewrite/--repair否则命令拒绝执行。--rewrite目前只支持 save 的 append/pick--ignore-missing目前只支持--unnamed--exclude-rx系列只在 rewrite/repair 下生效。远程协作有两种形态bup get -r host: ...本地推送到远程与bup on host get ...在远程执行拉取与bup-on(1)、bup-tag(1)、ssh_config(5)配合使用。十、SEE ALSObup-on(1)、bup-tag(1)、ssh_config(5)相关手册Documentation/bup-validate-refs.1.md检测.bupm删减、Documentation/bup-validate-object-links.1.md检测缺失对象、Documentation/bup-restore.1.md 与 Documentation/bup-ls.1.md验证修复结果发布说明note/0.33.5-from-0.33.4.md缺失对象问题的完整处理流程问题详析issue/missing-objects.mdbup get是 bup 中唯一集跨仓库引用搬运、按目标配置重写、损坏修复于一体的命令。掌握 METHOD 的语义差异与上下文选项的组合规则就能安全地在多仓库之间搬运、重分割与修复备份数据而退出码 3 与提交消息中的Bup-Repair-IDtrailer 则为修复操作提供了可靠的审计依据。赞分享灾备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 fsck 仓库校验与修复完全指南packfile 完整性检查、par2 恢复块与损坏恢复实战bup fsck 仓库校验与修复完全指南packfile 完整性检查、par2 恢复块与损坏恢复实战 bup 是一款基于 git packfile 格式的高效灾备CLI存储ScyllaDB nodetool repair 完全指南vnode 键空间的数据同步与修复实战ScyllaDB nodetool repair 完全指南vnode 键空间的数据同步与修复实战 导读 nodetool repair 是 ScyllaDB数据库分布式数据库后端大数据AutoSessionNeovim 自动会话管理神器AutoSessionNeovim 自动会话管理神器 项目介绍 AutoSession 是一款专为 Neovim 设计的自动会话管理插件充分利用了 Neov数据库分布式数据库后端大数据创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考