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

Snapshot-friendly backup / replication of a checked out git repository - without rsync'ing the .git directory

本地签出的 git 存储库应该镜像到备份机器,即 .git 目录和工作树。在此备份机文件系统上,快照 将被用来允许从任意 git 事故中轻松和 即时 恢复 [1]。 26=]

显而易见的解决方案是使用 rsync 并完成,但是常规 git gc 运行s 会创建新的和不同的 大.pack 文件,不适合快照[2]。对于源代码库,这个 gc 选项不能轻易更改。这也意味着 rsync 遍历 .git/objects 子文件夹中的所有内容,减慢它的速度。

直接使用 git 会更优雅(只需将所有已提交的工作推送到裸存储库就很容易),但这会留下工作树。服务器端回购配置 receive.denyCurrentBranch = updateInstead 将无法工作,因为工作树可能不干净。

会像 git push'ing,然后 rsync'ing 工作树加上 .git 减去 中的所有内容 objects 子文件夹工作?理想情况下,即使是正在进行的变基、合并或 cherry-pick 也会被复制。我想到 post-receive 上的服务器端挂钩 [3],但这些永远看不到客户端工作树状态。

1: 对于甚至 git reflog 也无济于事的事情,例如机器死机或 .git 损坏,或者只是懒惰的用户。

2:例如三个 ~10 行提交和一个 gc 运行 导致了 ca。正在传输 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/

如果你想同步整个工作树状态,你需要使用 Git 之外的一些系统。 Git 故意不将工作树状态同步到其他系统,也无法做到这一点。

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

不过,如果你真的想这样做,你可以采用push-and-rsync的方法。我个人会采取更简单的方法,只使用 rsync 并在重新打包时吃掉轻微的性能损失,因为它不太可能那么常见。默认情况下,git gc 只是用新对象创建一个新包,不会重新打包所有现有包,除非有超过 gc.autoPackLimit(默认 50)个包,所以 98% 的时间,您只需同步一个新包并删除旧的松散对象,以及工作树中的任何内容。

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