跳转至

一次 Git 与 rsync 同步翻车的复盘

总体结论

在基于 Git 与 rsync 的双目录同步方案中,如果没有明确唯一数据源,并在本地改动尚未进入版本控制之前执行覆盖型同步,就会导致数据被直接覆盖且无法恢复。这类问题的本质不是操作失误,而是同步策略设计存在结构性隐患。

问题经过与原因分析

该方案的基本结构是维护两个目录:一个作为 Git 仓库负责版本管理,另一个作为编辑目录用于日常修改。两者之间通过 rsync 进行同步。在实际操作中,常见流程是先执行远程拉取,然后再将仓库内容同步回编辑目录。

问题出在同步命令使用了带有 --delete 参数的 rsync。这一参数的含义并不是简单更新,而是将目标目录强制对齐到源目录状态,即删除所有不一致内容。当编辑目录中存在尚未同步到仓库的改动时,这些内容会被直接覆盖。由于这些改动尚未进入 Git 管理体系,因此无法通过版本控制恢复。

进一步分析可以发现,系统中实际上存在两个可以被修改的数据源:编辑目录与 Git 仓库。但在同步过程中,脚本默认仓库为权威状态,并直接覆盖编辑目录。这种未显式约定的主从关系在特定操作顺序下会产生冲突,从而引发数据丢失。

在移动设备环境中,共享存储的文件系统特性会进一步放大问题。文件修改时间和元信息可能不稳定,即使内容未发生变化,也可能被同步工具识别为差异,从而影响同步判断逻辑。这使得基于目录差异的检测机制不再可靠,既无法准确判断真实改动,也难以作为安全拦截手段。

改进思路与实践建议

要解决这一问题,关键在于明确系统中的唯一真源。应将 Git 仓库作为唯一权威数据来源,而编辑目录仅作为工作副本存在。所有修改必须先进入仓库,再参与后续的同步流程。

在操作流程上,应调整为:先将编辑目录的改动同步回仓库,在仓库内部判断是否存在未提交变更;如存在,则暂存这些改动;随后执行远程拉取操作;拉取完成后恢复本地改动;最后再将合并后的结果同步回编辑目录。这一流程确保所有冲突与变更都在 Git 体系内处理,而不是在同步过程中被覆盖。

同时,应避免在中间状态使用覆盖型同步工具。rsync 可以继续作为同步手段,但应仅用于最终结果的分发,而不是用于处理未纳入版本控制的数据。通过将同步行为与状态管理解耦,可以显著降低误覆盖的风险。

总结

这一问题的核心在于数据流设计不清晰。在存在多个修改入口的系统中,如果没有明确唯一真源,并且在错误的时机执行覆盖型同步,就会导致不可恢复的数据丢失。通过确立 Git 仓库为唯一数据源,并将所有变更统一纳入版本控制体系,可以从根本上避免此类问题的发生。