用例:我正在使用 Git 来跟踪个人笔记的历史记录,这些笔记会自动在我的电脑和手机之间同步(通过 Syncthing)。我git status
在从与上次不同的设备提交之前使用它来确保所有内容都已同步。
“已解决”的问题:问题是git status
更新索引,造成同步冲突,并且(取决于哪个设备“赢得”冲突)丢失提交。(正确的文件在那里;它们只是有新的扩展名sync-conflict-[timestamp]-[random code]
。手动解决很烦人。)
“解决方案”:从man git-status
我发现有一个--no-optional-locks
参数。根据man git
,这与设置相同GIT_OPTIONAL_LOCKS=0
(例如,从导出~/.profile
)。这可以很好地防止我意外创建同步冲突。
不良副作用:不幸的是,GIT_OPTIONAL_LOCKS=0
它~/.profile
对于设置它的设备/帐户来说是全局的,而不是对于实际需要它的存储库来说是本地的。这意味着环境变量甚至适用于我没有同步的大型存储库,其中后台索引刷新可能会显著提高性能。
寻求解决方案:因此我认为每个存储库的GIT_OPTIONAL_LOCKS=0
设置可以彻底解决我的问题。是否有可能实现相同的效果?
替代方法:也许我一开始就不应该在同步文件夹中使用 Git,而且整个方法注定会出现长期问题。如果是这样,那么有没有更好的方法,比如在 Git 内部同步设备之间存储库的简单方法?至少,在初始设置后,我正在寻找一个命令列表,我可以将其制作成脚本,以便在设备连接到同一个(不受信任的)本地网络时安全地同步设备之间的存储库(通过在两台设备上运行相同的同步脚本)。
答案1
一般来说,你不应该使用每个文件云同步服务来同步 Git 存储库。原因如下:
- 这些服务会逐个文件进行同步。但是,Git 存储库的完整性要求某些文件(例如对象)先于其他文件写入。同样,blob 必须在引用它们的树之前写入,否则存储库就会损坏。这些服务不理解这种顺序,也不保证这种顺序,并且它们不提供所需的 POSIX 语义。
- 由于文件在两边都发生变化,这些服务往往不能妥善处理冲突。这可能会给索引和目录中的其他文件
.git
以及工作树带来问题。Git 不希望其他服务在目录中创建随机文件.git
,因此您最终可能会得到大量奇怪的引用,以及其他问题。 - 这些服务在非静止状态下同步存储库。
rsync
在存储库上使用类似的东西是可以的,但只能在静止状态下使用,因为 Git 会将其所有对象正确写入文件系统。但是,云同步服务通常会监视任何更改并立即上传,这并不安全。 - Git 默认将系统特定信息(例如设备和 inode 编号)存储到索引中。由于这些数据几乎肯定会因系统而异,因此刷新索引的任何操作都必须读取整个工作树,因为数据已经过时。(使用
rsync
也有这个问题。)Git 的安全模型不允许互不信任的用户(例如不同系统上的用户)共享工作树,因此修复这个问题并不重要。此外,从索引中删除部分数据可能会导致无法git status
正确检测更改的情况。
如果您想安全地同步两个具有工作树的存储库,最好的办法是在存储库处于静止状态时使用 SSH 和 rsync。您可能还想使用--delete-after
以确保不会丢失数据。您可能还想设置为 和 以避免core.trustctime
将false
特定core.checkStat
于minimal
设备的数据序列化到索引中;但请注意,这可能会导致 Git 无法检测到 的一些更改git status
。
至于你最初的问题,答案是 Git 没有提供实现此目的的方法,但你当然可以创建git
一个 shell 函数来执行正确的操作(如果你愿意的话)。正如我所解释的那样,有更好的方法可以解决这个问题。