快照友好的备份/已检出git存储库的复制-无需rsync'.git目录

时间:2019-06-03 12:36:31

标签: git backup rsync snapshot

应该将本地签出的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½条建议:

  1. 完全关闭打包文件和gc,这将导致小文件 为将来的每一次变化而积累,最终将使事情成真 变慢。 gc.auto 0,gc.autopacklimit 0。

  2. 将最大压缩包大小设置为较小的数字,以使任何压缩包文件都不会变得太大,并且以后的差异层将捆绑在一起成为较小的压缩包文件。 pack.packSizeLimit。

  3. 对#2持不同意见:这与您想像的不一样,它只是将一个大文件打包成N个不同文件,每个文件中有相同的位,因此您没有保存任何内容。

  4. 如果您已经有一个巨大的打包文件,请在其旁边创建一个.keep文件。将出现新的打包文件,但它们与保存的文件相比有所不同,因此更小。

j:https://www.jwz.org/blog/2015/05/git-and-backups/

2 个答案:

答案 0 :(得分:2)

如果要同步整个工作树状态,则需要使用Git之外的某些系统。 Git故意不将工作树状态同步到其他系统,也不能这样做。

但是,话虽如此,我敦促您重新考虑是否要同步工作树的各个部分,例如索引。索引不包含在机器之间传输的索引,因为它包含诸如索引节点号和文件时间戳之类的信息。此外,Git存储库的安全模型假定工作树是受信任的,并且可以在不受信任的存储库上进行的唯一安全操作是克隆和获取。

但是,如果您确实想这样做,则可以执行“推送并同步”方法。我个人会采用一种更简单的方法,即只使用rsync并在重新打包时承受较小的性能损失,因为这不太常见。默认情况下,git gc只会使用新对象创建一个新包,并且不会重新包装所有现有的包,除非有超过gc.autoPackLimit个(默认为50个)包,因此98%的时间,您只需重新同步一个新包并删除旧的松散对象,再加上工作树中的所有内容即可。

答案 1 :(得分:1)

我的方法是使用 git,而不是强迫它做奇怪的事情。这意味着:在后仓库中使用git pushgit fetch。要同时捕获工作树状态,您可以首先调用类似git stash push --all的名称(或仅调用--include-untracked而不是--all)。然后,确保还将refs/stash引用也镜像到备份存储库中。因为git现在已经为工作树中的所有内容编写了对象,所以这些对象也可以转移到备份中。