同步两个git存储库的所有对象

时间:2013-11-30 17:16:43

标签: git

在我们的服务器上,我们有一个生产git存储库,其周围有一些专有的工作流,恰好只在一些reflog中保存重要的提交。出于备份目的,我们希望将整个存储库同步到第二个存储库。

一种方法是简单的git push --all。不幸的是,这只会推送一些已知引用引用的对象,而忽略那些仅由某些reflog引用的对象。有没有办法告诉git push推送reflogs(以及相应的提交!)? (我目前只能想到手动创建假章鱼与reflog的所有条目合并。)

另一种方式是文件系统级别的某些备份,如rsync。这可能会有效但存储库非常大,git可能会重新打包它的提交。因此,这可能需要很长时间。

有没有办法列出两个存储库中的所有对象,比较它们,只传输丢失的对象?这种任务是否已经有一些内置功能?手动执行此操作的最佳方法是什么,否则?

2 个答案:

答案 0 :(得分:0)

如果在reflag中保留这些特定提交真的很重要,那么为它们提供一些标签(标签或反映“专有工作流程”的分支名称)可能是值得的。不知道更多,想要保留这些提交似乎有风险,但除了reflags引用它们之外没有任何东西,这意味着它们可能会在未来的某个时间意外地被垃圾收集。

但是,不要再质疑你的过程了;)我不相信有一个命令能够准确地提供你所需要的东西(两个存储库中的完整对象列表)。我能想到的最接近的是git reflag本身,它接受所有日志选项来过滤和格式化reflag中的对象。如果你可以为日志制定一个合适的查询,也许你可以让它输出你发现“重要”的提交对象,但不会在任何其他引用中列出,并将这些结果提供给git-pack-objects。 (你对章鱼合并的想法是一种很有前途的方法来识别它们)

答案 1 :(得分:0)

没有什么可以推动(或拉动)reflog,但是通过使用refs/空间的分层特性来构成临时(或者甚至可能不是那么临时)的参考,很容易“伪造”它们。推动那些。然后,您可以运行推送后脚本 - 甚至可以直接从post-receive执行此操作 - 使用git update-ref在另一端构建所需的reflog。

假设(出于设计草图的目的),您选择refs/sync/作为新名称空间的顶层。然后:

# find reflogs - change this to use the ones you care about
unfiltered=$(
    for refname in $(cd $(git rev-parse --git-dir)/logs &&
            find * -type f -print); do
        echo $refname
    done
)

filtered=... # something ...

filtered="HEAD refs/heads/master" # for now

for reflog in $filtered; do
    # change name from (.*)@{([0-9]+)} to \1/\2
    # (keep commit ID at left)
    git reflog --no-abbrev $reflog |
        sed -n 's,\([^ ]*\) \(.*\)@{\([0-9][0-9]*\)}:.*,\1 \2/\3,p'
done

此输出(到目前为止)是一系列哈希值和名称,因此可以通过管道传递给:

while read hash name; do
    git update-ref -m 'create for transport' refs/sync/$name $hash
done

现在您可以git push远程refs/sync/命名空间,然后删除所有refs/sync/名称(删除此处创建的名称,或者只删除所有refs/sync/名称在前面 - 你可能想要这样做,以防其中一个更新序列被中断):

git for-each-ref --format 'git update-ref -d %(refname)' refs/sync/ | sh

在遥控器上,收到refs/sync/*引用后,你可以通过反转上面的过程将它们变回reflog条目(它甚至更容易一些,你只想用最终组件进行数字反向排序,这样最旧的日志条目首先被更新引用。

正如另一个答案所说,在很大程度上依赖于reflogs可能不是那么明智。您可以使用上述技术将现有的reflog条目转换为更永久的条目(例如已经存在于refs/tags/中的标记;例如,您可以使用子集名称空间,refs/tags/autotag/NNN)。