应该将本地签出的git存储库镜像到备份计算机,即.git
目录和工作树。在此备份计算机上,将使用快照文件系统,以便从任意git事故[1]中轻松且即时恢复。
显而易见的解决方案是使用rsync
并完成操作,但是常规的 git gc 运行会创建新的和不同的大.pack 文件,这些文件无法播放很适合快照[2]。对于源存储库,无法轻易更改此gc选项。同样,这也意味着rsync
遍历.git/objects
子文件夹中的所有内容,从而降低了速度。
直接使用git
会更优雅(将所有已经提交的工作推送到裸仓库中将很容易),但这会留下工作树。服务器端存储库配置receive.denyCurrentBranch = updateInstead
无法正常工作,因为工作树可能不干净。
是否需要先进行git push
运算,然后rsync
运算工作树以及.git
减去 objects
子文件夹工作中的所有内容?理想情况下,甚至可以复制正在进行的rebase,merge或cherry-pick。我想到了post-receive
上的服务器端钩子[3],但是这些钩子从未看到客户端工作树状态。
1:对于什至git reflog也无济于事的事情,例如计算机快死了或.git
损坏了,或者只是懒惰的用户。
2:例如3〜10行提交和gc运行导致大约。正在传输500MB的文件。
3:服务器端挂钩意味着无法通过普通的scp -r
恢复该存储库,但这是可以接受的。
更新:
似乎是不可能的,例如jwz已在2015年发现[j],解决方法:
[..],这里有3½条建议:
完全关闭打包文件和gc,这将导致小文件 为将来的每一次变化而积累,最终将使事情成真 变慢。 gc.auto 0,gc.autopacklimit 0。
将最大压缩包大小设置为较小的数字,以使任何压缩包文件都不会变得太大,并且以后的差异层将捆绑在一起成为较小的压缩包文件。 pack.packSizeLimit。
对#2持不同意见:这与您想像的不一样,它只是将一个大文件打包成N个不同文件,每个文件中有相同的位,因此您没有保存任何内容。
如果您已经有一个巨大的打包文件,请在其旁边创建一个.keep文件。将出现新的打包文件,但它们与保存的文件相比有所不同,因此更小。
答案 0 :(得分:2)
如果要同步整个工作树状态,则需要使用Git之外的某些系统。 Git故意不将工作树状态同步到其他系统,也不能这样做。
但是,话虽如此,我敦促您重新考虑是否要同步工作树的各个部分,例如索引。索引不包含在机器之间传输的索引,因为它包含诸如索引节点号和文件时间戳之类的信息。此外,Git存储库的安全模型假定工作树是受信任的,并且可以在不受信任的存储库上进行的唯一安全操作是克隆和获取。
但是,如果您确实想这样做,则可以执行“推送并同步”方法。我个人会采用一种更简单的方法,即只使用rsync
并在重新打包时承受较小的性能损失,因为这不太常见。默认情况下,git gc
只会使用新对象创建一个新包,并且不会重新包装所有现有的包,除非有超过gc.autoPackLimit
个(默认为50个)包,因此98%的时间,您只需重新同步一个新包并删除旧的松散对象,再加上工作树中的所有内容即可。
答案 1 :(得分:1)
我的方法是使用 git,而不是强迫它做奇怪的事情。这意味着:在后仓库中使用git push
和git fetch
。要同时捕获工作树状态,您可以首先调用类似git stash push --all
的名称(或仅调用--include-untracked
而不是--all
)。然后,确保还将refs/stash
引用也镜像到备份存储库中。因为git现在已经为工作树中的所有内容编写了对象,所以这些对象也可以转移到备份中。