题记与说明
- 日期:2026-11-04
- 前缀:knowledge-8e9pv6gy-0
- 类型:主题研究(多来源精读 + 本地实测验证)
- 来源清单(本次实际检索并精读 8 篇,均有原文引述;另有 2 组本地实验):
- Syncthing 官方文档《Understanding Synchronization》(docs.syncthing.net, v2.1.0 对应版本页)— https://docs.syncthing.net/users/syncing.html
- Syncthing 官方文档《File Versioning》— https://docs.syncthing.net/users/versioning.html
- rclone 官方文档《rclone sync》命令页 — https://rclone.org/commands/rclone_sync/
- rclone 官方文档《Docs》总页之
--backup-dir段 — https://rclone.org/docs/ - rclone 官方文档《rclone check》命令页 — https://rclone.org/commands/rclone_check/
- rclone 官方文档《Google drive》后端页 — https://rclone.org/drive/
- Google Drive 官方帮助《Check activity & file versions》— https://support.google.com/drive/answer/2409045
- Rafael Epplée 博客《Automatically resolve Syncthing conflicts using a three-way merge》(2020-09-17)— https://www.rafa.ee/articles/resolve-syncthing-conflicts-using-three-way-merge/
检索方式说明:本次全程有网络。Syncthing/rclone/rafa.ee 各页经网页抓取器读取全文并结构化提取;support.google.com 第一次抓取超时,改用 webReader 成功读取当前版本页面(可折叠小节"Download recent versions"等未展开,正文关键句已取得)。另在本地 Windows 11(rclone v1.75.1)跑通 2 组冒烟实验,验证rclone check --combined与sync --backup-dir的文档行为。
一、来源精读与关键引述
1. Syncthing《Understanding Synchronization》——冲突是显式留痕的,不自动合并
Syncthing 的底层是块级 + SHA256:文件被切成 128 KiB–16 MiB 的等大块(最后一块可小),每块算 SHA256 形成 block list("the offset, size and hash of all blocks")。同步时逐块对比当前与目标版本,块来源可以是本地磁盘拷贝或远端网络获取。接收到的块都要校验:
"If it matches the block is written to a temporary copy of the file, otherwise it is discarded."
(块哈希不匹配就被丢弃重取——传输完整性在协议层保证,这是三套工具里唯一做到"传输中逐块校验"的。)
变更检测靠每小时全量扫描 + 文件系统 watcher(fsWatcherDelayS 默认 10 秒延迟,删除延迟 1 分钟),扫描比较 "modification time, size or permission bits",变了才重新算哈希。
核心的冲突机制:当文件在两台设备上"同时被修改且内容确实不同"时,Syncthing 不选边合并,而是双方都保留,其中一方被重命名为冲突副本:
- 命名格式:
<filename>.sync-conflict-<date>-<time>-<modifiedBy>.<ext> - 谁改名:"The file with the older modification time will be marked as the conflicting file and thus be renamed." —— mtime 新者胜,旧者被改名保留。
- mtime 平局时的决胜规则很奇特:"the device which has the larger value of the first 63 bits for its device ID will be marked as the conflicting file"——设备 ID 前 63 位更大的那份改名。纯机械规则,与内容好坏无关。
- 修改 vs 删除冲突、且删除获胜时:"the file is renamed to a conflict copy as above"——即使"删除方"赢了,被删内容也不消失,而是变成冲突副本。这是"恢复友好"设计的关键一环。
最重要的传播警告:
"Beware that the <filename>.sync-conflict-...<ext> files are treated as normal files after they are created, so they are propagated between devices."
(冲突文件一经创建就被当作普通文件同步到所有设备。官方理由:冲突"在别处同样是冲突",Syncthing 无法替用户判断哪份是"最好的"。副作用是冲突文件会随集群扩散——清理一台设备上的冲突文件前要想清楚。)
另外与"冲突"沾边的还有大小写冲突:在不区分大小写的系统(Windows/macOS/Android)上,同名不同大小写的两个变体只能拉取其一,"Which one 'wins' is currently not predictable"——官方明说大小写胜负不可预测,只能人工统一命名。
2. Syncthing《File Versioning》——版本化只保护"远端来的变更"
版本化的定义:在文件被删除或"被集群中更新的版本替换"时归档旧副本,按文件夹、按设备配置,默认关闭。适用范围的引述是全篇最要紧的一句:
"Versioning applies to changes received from other devices."
(只有从其他设备收到的变更才触发归档。本地编辑、本地误删根本不进 .stversions——Syncthing "will not and can not archive the old version"。这意味着版本化是冲突恢复网,不是本机快照。)
四种版本化类型与保留参数:
| 类型 | 行为 | 保留参数 |
|---|---|---|
| Trash Can(垃圾桶) | 被删/被替换文件移入 .stversions,同名直接覆盖 | cleanoutDays;"to zero prevents any files from being removed" |
| Simple | 同上,但保留时间戳版本 | cleanoutDays + keep(如 5 = 每文件 5 个带时间戳版本) |
| Staggered | 分间隔保留:第 1 小时每 30 秒 1 版 → 第 1 天每小时 1 版 → 前 30 天每天 1 版 → 之后每周 1 版,直到 maxAge | maxAge("Set to 0 to keep versions forever") |
| External | 替换前调用外部命令,脚本必须自行移走文件否则报错 | 无;占位符 %FOLDER_PATH%/%FILE_PATH% |
External 类型有安全警告,值得逐字记录:
"You should consider file paths as untrusted user input."
(文件路径当不可信输入对待——外部脚本若用 shell 包一层可能被拒绝执行,文档给了 Unix/PowerShell/Recycle Bin 三个示例脚本并注明可移动存储上文件会被真删。)
存储位置与文件系统限制:
"please ensure that it's on the same partition or filesystem as the regular folder path, as moving files there may otherwise fail."
(.stversions 自定义路径必须与同步文件夹同分区/同文件系统——它是"移动"不是"复制",跨分区移动会失败,恢复能力随之失效。)
清理参数:cleanupIntervalS(清理周期,"Zero to disable periodic cleaning. Limited to one year");cleanoutDays("Zero means to keep forever")。恢复方式文档未写专门流程——就是从 .stversions 手动取回(文件名带 ~时间戳 后缀,如 notes~20200917-173218.md)。
3. rclone sync——破坏性语义 + 四重安全网
rclone sync 的定义就带着破坏性:
"Make source and dest identical, modifying destination only." / "Destination is updated to match source, including deleting files if necessary"
(目标是"让目标与源一模一样,包括删除"。方向性是绝对的:只改目标。)
官方把安全网放在最前面:
"Important: Since this can cause data loss, test first with the --dry-run or the --interactive/i flag."
四重安全网,按防线排列:
- 演练:
-n/--dry-run("Do a trial run with no permanent changes")、-i/--interactive逐个确认。 - 出错即停删:"Files in the destination won't be deleted if there were any errors at any point."——任何环节出错就不执行删除;
--max-delete/--max-delete-size限制删除数量/体量,超限中止。 - 被覆盖/被删文件留底:
--backup-dir——"When using sync, copy or move, any files which would have been overwritten or deleted are moved in their original hierarchy into this directory."(按原目录层级移入备份目录)。后缀建议自己带时间戳:--suffix $(date +%F)或 PowerShell--suffix $(Get-Date -Format 'yyyy-MM-dd');同后缀文件已存在则覆盖。硬性约束逐字记录:"The remote in use must support server-side move or copy and you must use the same remote as the destination of the sync. The backup directory must not overlap the destination directory without it being excluded by a filter rule." - 无删除语义:不想删就用
rclone copy,或者--suffix("suffix added to changed files")。
判定"文件是否相同"的默认规则:按大小 + 修改时间或 MD5SUM;-c/--checksum 则改为 "Check for changes with size & checksum (if available, or fallback to size only)"——注意 fallback:远端没有 hash 时退化为只比大小,--checksum 不是内容全等证明,是更严格的变更检测(论坛帖原话:"--checksum isn't about transfer safety but about more accurately detecting file changes")。
4. rclone check——独立的审计命令,不改数据
"Checks the files in the source and destination match." / "compares sizes and hashes (MD5 or SHA1) and logs a report of files that don't match. It doesn't alter the source or destination."
关键开关:
--download:"it will download the data from both remotes and check them against each other on the fly."——不信任清单比对时,把两边数据真正拉下来边传边算哈希。这是内容级全量校验,代价是全量带宽。--size-only:"it will only compare the sizes not the hashes as well. Use this for a quick check."--one-way:"it will only check that files in the source match the files in the destination"——目标端多出来的文件不报。--checkfile HASH:对照 SUM 格式哈希清单校验(相当于自带基线清单)。
机器可读差异报告 --combined 的五个符号(sync 命令页同款):
| 符号 | 含义 |
|---|---|
= | 两端一致 |
+ | 目标缺失(仅源有) |
- | 源缺失(仅目标有) |
* | 两端都有但不同 |
! | 读取或哈希出错 |
并行度默认 8("The default number of parallel checks is 8",--checkers 调整)。加密远端要用 cryptcheck("is able to check the checksums of the encrypted files"——普通 check 对 crypt 远端只能比密文,比不了明文哈希)。
5. rclone Google Drive 后端——hash 支持、修订机制与已知坑
hash 支持的引述:
"Hash algorithms MD5, SHA1 and SHA256 are supported." / "All files have MD5 hashes"
但有两个边界,逐字记录:
"a small fraction of files uploaded may not have SHA1 or SHA256 hashes especially if they were uploaded before 2018"
"Corrupted checksums are caused by Google modifying the image/video but not updating the checksum"
(2018 年前的老文件可能缺 SHA1/SHA256;Google 相册转存的图片/视频被 Google 改了内容却没更新 checksum——--drive-skip-checksum-gphotos 专门绕开。MD5 是 Drive 上唯一全覆盖的 hash。)
修订机制(版本化的云端形态):
"Google drive stores revisions of files. When you upload a change to an existing file to google drive using rclone it will create a new revision."
"They are deleted after 30 days or 100 revisions (whatever comes first)."
"They do not count towards a user storage quota."
(覆盖上传自动产生新修订;保留规则 30 天或 100 个版本先到先删;不占配额——这是 Drive 对个人最慷慨的一点。--drive-keep-revision-forever:"Keep new head revision of each file forever." 可钉住版本。)
删除与回收站:"By default rclone will send all files to the trash when deleting files"(默认进回收站而非永久删除);rclone cleanup remote: 会永久清空回收站,且实际清空"minutes to days"后才生效。时间精度:"Google drive stores modification times accurate to 1 ms"——比多数文件系统细,mtime 比对不受毫秒截断坑影响。
Drive 特有的重复文件坑:
"drive will duplicate a file that rclone uploads. Drive unlike all the other remotes can have duplicated files."
(其他远端用唯一键,Drive 允许同名同内容对象共存——rclone 遇到会用 rclone dedupe 处理。)另有目录列表缓存延迟导致的反复重拷,"waiting roughly an hour helps"。配额硬限制:上传 750 GiB/天、下载 10 TiB/天,--drive-stop-on-upload-limit 可把超限从警告升级为致命错误——对备份脚本很重要,否则半途失败静默继续。
6. Google Drive 官方帮助——版本历史的 UI 边界
正文关键句(webReader 实读):
"Only the most recent versions of past documents will be saved, unless you click Keep forever."
以及开篇的类型区分:
"Version history for Google Docs, Sheets, and Slides is different than history for .pdf files, images, and other files stored in Drive."
(Google 原生文档走内部版本历史;PDF/图片等二进制文件走上传修订——两套机制在 UI 上都叫"version history"但行为不同。与 rclone 文档的"30 天/100 修订"互为印证:UI 的"Keep forever"对应 API 侧钉住修订。页面还提供了活动记录面板(Info → Activity)查看谁在何时编辑/移动/上传了什么——审计能力在云端有入口。)
7. 社区实践(rafa.ee)——用版本化文件当 git 三路合并的公共祖先
作者动机:"for other files like todo lists, notes etc. that get changed on multiple devices before being synced, syncthing doesn't know how to combine the changes and creates a conflict file."(Syncthing 只知道冲突、不知道合并——对纯文本多端编辑场景体验很差。)
解法是把 Syncthing 的版本化当 git merge-file 的公共祖先来源:
"Enter git merge-file. It's bundled with git, but can run completely independent of any git repository. It automatically merges two versions of a file with little to no conflicts."三路合并的原理引述:"it looks at three files - the two conflicting edited versions, and their common ancestor. …Using this, git can figure out whether lines missing in one of the versions were actually added or removed - with only two files, this would be impossible."
实操命令(作者实测):
git merge-file notes.md .stversions/notes~<xxxxx>.md notes.sync-conflict-<xxxxx>.md即:当前胜出版本、.stversions 里的公共祖先(~时间戳 文件)、.sync-conflict- 失败副本,三者做三路合并,结果写回 notes.md。作者示例中两端各加一行,合并后两行都在。
关键坑(与官方文档互证):
"Since syncthing only creates backups in.stversionswhen receiving changes from a remote machine and not when the file is modified locally, you might end up in a situation without a common ancestor in.stversions."
(本地修改不进版本库 → 公共祖先可能缺失。作者的 fallback:touch empty.md 用空文件当祖先——"This might result in more conflicts than usual, but in general git is pretty good at figuring out common lines"。)
应用边界:方法只对纯文本成立(作者的前提是 "storing data in plain text files");.m3u 播放列表可用 git merge-file --union 无脑保留双方行。作者自述 "I've only been running this by hand since I didn't have too many conflicts",建议写个脚本定期扫描 .sync-conflict-* 批量洗。二进制文件不适用——三路合并对二进制无从谈起,只能选边或手工用专门工具。
二、本地实测验证(本次会话实际运行)
环境:Windows 11(win32 10.0.26200),rclone v1.75.1。
实验 1:rclone check --combined 的符号报告。构造 src 与 dst 各含 a.txt(内容一致)与 b.txt(内容不同),运行:
rclone check -v --combined combined.txt /tmp/rclone-check-test/src /tmp/rclone-check-test/dst输出:
Errors: 1 (retrying may help)
Checks: 2 / 2, 100%, Listed 4
2026/11/04 05:04:04 NOTICE: Failed to check: 1 differences found
--- combined.txt ---
= a.txt
* b.txt与文档逐项吻合:= 标一致、* 标"两端都有但不同"、发现差异时以错误退出("1 differences found")——check 可直接接进 cron/任务计划做"无差异即通过"的门禁。
实验 2:rclone sync --backup-dir --suffix 的留底行为。dst 中放一个 src 没有的 deleted.txt(sync 时会被删除)与内容相同的 a.txt,运行:
rclone sync --backup-dir /tmp/rclone-bd-test/backup --suffix 2026-11-04 src dst结果:
--- dst --- a.txt (被删文件从 dst 消失)
--- backup --- /tmp/rclone-bd-test/backup/deleted.txt2026-11-04验证了三件事:被删文件确实按原层级移入 --backup-dir;--suffix 直接拼在文件名末尾无分隔符(deleted.txt2026-11-04 而非 deleted.txt.2026-11-04)——想留扩展名识别要用 --suffix-keep-extension 或把日期写成 .2026-11-04 形式;内容相同的文件不动。
三、横向对比:三套工具的冲突、恢复、校验模型
| 维度 | Syncthing | rclone | Google Drive 原生 |
|---|---|---|---|
| 冲突模型 | 内容级、显式留痕:mtime 新者胜,旧者改名 *.sync-conflict-<日期>-<时间>-<设备> 保留,且作为普通文件传播到全集群 | 无冲突概念:单向 sync 语义"最后跑的赢",留痕靠 --backup-dir 把被覆盖/被删文件移走 | 修订级、云端兜底:覆盖上传产生新修订(30 天/100 个),Web UI 可回滚;并发编辑 last-write-wins,无引擎层冲突检测 |
| 恢复路径 | .stversions 手动取回;冲突副本 + 版本化文件可做 git merge-file 三路合并 | --backup-dir 层级留底 + --suffix 时间戳;默认进回收站(Drive 后端) | Web UI 版本历史("Keep forever" 钉住);回收站 |
| 传输完整性 | 块级 SHA256 逐块校验,不匹配即丢弃 | 每次传输后校验 hash;check 命令做清单级审计 | MD5 全覆盖,SHA1/SHA256 部分覆盖(2018 前老文件缺失) |
| 校验深挖 | 扫描时重算哈希 | rclone check --download 全量拉取比对;cryptcheck 处理加密远端 | GPhotos 转存文件 checksum 不可信;Drive 允许重复对象需 dedupe |
| 版本化成本 | .stversions 占本地空间(同分区限制) | backup-dir 占目标端空间,需自己清理 | 修订不占配额——三套中最慷慨 |
| 主要盲区 | 本地编辑不进版本库;冲突文件扩散;大小写冲突胜负不可预测 | --checksum 无 hash 时退化为只比大小;backup-dir 不得与目标重叠 | 修订 30 天/100 个自动滚动删除;原生文档与二进制文件版本机制不同 |
四、七维提取
核心问题
多设备/多副本之间同步文件时,"同步"(保持一致)与"备份"(可回滚)是两种语义,几乎每个工具都把责任推给用户:修改-修改、修改-删除冲突如何呈现?被覆盖或误删的内容从哪里恢复?以及最容易被忽略的——同步"完成"之后,如何证明两端数据真的一致而不是只比了文件名和大小?本次精读回答:三个代表工具(实时双向的 Syncthing、脚本式单/双向的 rclone、云原生的 Google Drive)各自把这三个问题解决到什么程度、缺口在哪、怎么组合补齐。
主要主张
- Syncthing 的冲突是"显式留痕、拒绝合并":mtime 新者胜,旧版本重命名为
*.sync-conflict-*保留而非丢弃,甚至删除获胜时被删内容也变成冲突副本;但冲突文件会被当普通文件传播到所有设备,且没有任何自动清理/合并机制。 - Syncthing 版本化是单向保护网:"Versioning applies to changes received from other devices"——只保护从远端收到的变更,本地编辑损毁不进
.stversions;版本目录必须与同步文件夹同分区(移动语义)。 - rclone sync 是破坏性语义,靠安全网而非安全设计:默认含删除;官方第一句就是 "test first with --dry-run or --interactive";防线依次为演练 → 出错不删/
--max-delete→--backup-dir层级留底 → 实在不行用copy。 - rclone 的校验是分层的三档:传输后自动 hash 校验(默认)→
rclone check清单级审计(--combined五符号机器可读)→check --download内容级全量校验;--checksum只是更严的变更检测,无 hash 时退化为比大小,不等于内容全等证明。 - Google Drive 的版本化慷慨但滚动:修订 30 天/100 个自动删、不占配额、UI 可回滚(Keep forever 钉住);但只覆盖"上传变更",MD5 是唯一全覆盖 hash,GPhotos 转存文件 checksum 不可信。
- 冲突的"内容级"恢复上限是纯文本:
git merge-file+.stversions公共祖先可自动三路合并 Syncthing 冲突(社区验证),但二进制冲突只能选边。
方法
主题研究方法:先以三组关键词检索(Syncthing conflict/versioning、rclone checksum/backup-dir/check、Google Drive version history/rclone drive),收敛到 8 个来源——7 个官方文档 + 1 个社区实践——逐一全文抓取、提取关键引述;再用 2 组本地冒烟实验(rclone check --combined 符号报告、rclone sync --backup-dir --suffix 留底行为)把文档声明落到可复现的命令输出;最后横向对比三套工具的冲突/恢复/校验模型。
数据与证据
- 官方引述 20+ 条(上文逐字标注出处),关键的三条:Syncthing "The file with the older modification time will be marked as the conflicting file";rclone "any files which would have been overwritten or deleted are moved in their original hierarchy into this directory";rclone drive "They are deleted after 30 days or 100 revisions (whatever comes first)"。
- 本地实测 2 组:
rclone check -v --combined输出= a.txt/* b.txt且以 "1 differences found" 错误退出(rclone v1.75.1);sync --backup-dir --suffix 2026-11-04后dst/deleted.txt移至backup/deleted.txt2026-11-04——--suffix无分隔符直接拼接是实测才发现的行为细节,文档未明示。 - 证据充分性:官方文档间互相印证(如 Drive 修订保留规则在 rclone 文档与 Google 帮助页两侧一致;Syncthing 本地变更不入版本库在官方文档与 rafa.ee 实践两侧一致),核心主张可信度高。
结论
三套工具对"同步与备份"给出三种哲学:Syncthing 把冲突变成显式对象(冲突文件 + 版本库),恢复靠人工从留痕里取,胜在永不静默丢数据;rclone 把安全变成脚本纪律(dry-run/interactive、backup-dir、max-delete、check 审计),胜在每一步可自动化、可审计;Google Drive 把版本变成云服务(修订 + 回收站 + 活动记录),胜在零成本但受 30 天/100 版滚动限制。三者互补而非互斥——校验恰好构成完整链条:Syncthing 传输中块级 SHA256 → rclone 传输后文件级 hash → rclone check 清单级 → check --download 内容级 → Drive 侧 MD5 基线。组合方案:Syncthing 文件夹全开 Staggered 版本化(maxAge=0 或 365)承担日常恢复与三路合并原料;rclone 到 Drive 的同步脚本固定模板 sync --interactive --backup-dir remote:old --suffix $(date +%F) --max-delete 100;每周 rclone check --combined 出差异报告归档;关键 Drive 文档用 "Keep forever" 钉版本。
局限
- Syncthing 侧:官方 syncing 页未覆盖
.stignore忽略冲突文件的做法(需另查 Ignoring Files 页);冲突文件双向传播可能扩散污染;大小写冲突"胜负不可预测"是官方承认的。 - rclone 侧:总文档页过长被截断,
--backup-dir与目标重叠时的具体报错文本未取得;--checksum的 fallback 行为意味着"无 hash 远端 + 只比大小"仍有内容损坏漏检窗口。 - Drive 侧:GPhotos 转存文件 checksum 不可信、Drive 允许重复对象、目录列表缓存延迟——rclone 文档自己列出的三个坑没有 protocol 层解法,只有绕行 flag。
- 方法局限:
git merge-file三路合并仅适用纯文本;rafa.ee 是 2020 年个人实践(作者自述手工运行),非官方背书;本地实测只覆盖本地目录与本地 backup-dir,未对真实 Google Drive remote 验证(本次无凭据,--backup-dir要求 server-side move/copy,云端行为可能有差异);Google 帮助页的折叠小节(下载/上传/删除版本的具体 UI 步骤)未展开读取。 - 与既有笔记
2026-10-31-knowledge-fexxiou8-4(321 备份原则)的重叠部分(Drive 修订、回收站)本文从同步工具视角再取一次,两篇互为补充而非重复。
对我的启发
- 把"同步、版本化、校验"当三个正交机制设计,不指望任何一个工具全包——这是三套文档共同的潜台词:Syncthing 只保证传输完整不管本机快照,rclone 只保证脚本纪律不管实时,Drive 只保证云端修订不管本地。
- 校验分层的迁移价值:传输校验(默认)≠ 清单校验(check)≠ 内容全量校验(--download)的三档模型,可直接搬到任何数据管道——比如我自己的笔记库/代码库同步脚本,最低配也应该有"周任务 check + 差异报告归档"这一档。
- 实测补文档的行为细节最值钱:
--suffix无分隔符拼接、check发现差异以错误码退出可当门禁——这些只有跑一遍才知道,写进自己的脚本模板:rclone sync --interactive --backup-dir remote:old --suffix "$(date +%F)" --max-delete 100 src dst。 - 冲突文件的处置要有纪律:
.sync-conflict-*会扩散,定期(如每周)用git merge-file洗一遍纯文本冲突、清掉已合并的副本,比攒到半年后面对几十个冲突文件现实得多;对.stversions记住两点——本地编辑不进库、必须同分区。 - 与 fexxiou8-4 那篇的 3-2-1 框架拼起来正好完整:321 管副本数量与介质,本篇管副本之间"如何同步不互相毁、如何证明一致"。