备份 GitHub 仓库

61

如何在 GitHub 托管的 Git 仓库中创建本地备份,满足以下要求:

  1. 本地备份应该是一个裸仓库。

  2. 备份应包含所有分支。

  3. 应该容易(增量地)更新备份。

基本上,我想要一个完美的镜像,并且可以方便地更新。为此,可以使用以下命令:

git clone --mirror git://github.com/...

我想到了 rsync,但据我所知,它不允许轻松更新(我必须删除并重新创建本地备份)。此外,git clone 的镜像选项似乎是最近的事情,一些我正在使用的系统上没有它(这些系统运行着稍旧版本的 git)。

您对这种问题有什么推荐的解决方案吗?

4个回答

50

我不确定它是否能满足你的所有要求,但你可以查看git bundle

git bundle

这个命令支持使用归档将对象和引用打包到原始机器上,然后通过移动归档文件并使用git fetchgit pull导入到另一个存储库中。

我喜欢这个解决方案的原因是它只生成单个文件,里面正好有我想要的内容。

git bundle仅会打包通过git-show-ref显示的引用,包括heads、tags和remote heads。

machineA$ git bundle create file.bundle master

注意:评论区Kent Fredric提到了来自git rev-list的一个细节:


--all

假装所有的引用都列在命令行中作为<commit>

他补充道:

您当前的捆绑包只会捆绑提交的父级,您可能需要指定--all以获得关于所有内容(作为master的后代的分支)的完整捆绑包。

要查看区别:

$ git bundle create /tmp/foo master
$ git bundle create /tmp/foo-all --all
$ git bundle list-heads /tmp/foo
$ git bundle list-heads /tmp/foo-all

4
当前的捆绑包只会捆绑指定提交的父节点,如果想获取完整的捆绑包(包括主分支下的所有子分支),你可能需要使用 --all 参数。为了创建一个只包括主分支的捆绑包,可以使用命令 git bundle create /tmp/foo master;为了创建一个包括所有分支的捆绑包,可以使用命令 git bundle create /tmp/foo-all --all;通过命令 git bundle list-heads /tmp/foo 和 git bundle list-heads /tmp/foo-all 可以查看这两个捆绑包的头信息。这个小改动非常重要。 - Kent Fredric
2
我尝试了所有这些方法,但是分支从未保存在捆绑包中。 - haysclark
@Infinite,https://dev59.com/VnA65IYBdhLWcg3wyRyk#3639182 这个更好吗?(至少在开头的 hostA$ git bundle create hostA.bundle --branches --tags 部分是这样的吗?) - VonC
3
请参阅:从捆绑备份中恢复 Git 存储库 - Martin Thoma

49

创建镜像的方法:

git clone --mirror git://github.com/user/project.git

更新:

cd project.git
git remote update

要在不改变当前目录的情况下进行更新:

git --git-dir project.git remote update

5
这个步骤是获取远程存储库的完整本地副本的正确方法;之后可以使用 git bundle create --all 将整个存储库导出为单个文件。 - Lee
@ Lee,当我尝试从project.git/内部执行git bundle create --all ../project.bundle时,我收到了“error: rev-list died”的错误提示。 - Jonathon Reinhart
1
@李阿,没事了。--all是传递给git-rev-list的参数。因此,命令中正确的顺序应该是git bundle create ../project.bundle --all - Jonathon Reinhart

10

但据我所知,这样做不利于轻松更新(我需要删除并重新创建我的本地备份)。

不确定你的意思是什么,更新应该很简单,只需要:

git fetch

git clone 命令会获取远程分支所能看到的所有refs/commits。

git clone --mirrorgit clone --bare 并没有太大区别。[来源]

唯一显著的区别是 git remote add --mirror 缩写命令。

(查看git help add获取不同的行为)

如果你真的很担心,可以这样做:

git clone --no-hardlinks --mirror $original $dest 

如果它们本来就在同一个文件系统上,那么它们之间只会有微小的差异。如果你真的很担心,可以将整个目录打成tar.(gz|bz2)压缩包,然后备份。


0
你所询问的内容在 git 的限制内相当困难。问题在于,无论是克隆还是获取,都不会默认提供所有分支。请看这个问题:

以下是克隆具有多个分支的 repo 的示例:

% git clone -o tufts linux.cs.tufts.edu:/r/ghc/git/experimental.git
Initialized empty Git repository in /usr/local/nr/git/ghc/experimental/.git/
% cd experimental/
% git fetch
% git branch -a
* head
  tufts/HEAD
  tufts/experimental
  tufts/head
  tufts/norman
% git branch --track experimental tufts/experimental
Branch experimental set up to track remote branch refs/remotes/tufts/experimental.
% git branch --track norman tufts/norman
   ...

你可以看到,通过编程克隆每个分支会有一些棘手的问题。

如果 Github 提供了访问 rsync 或 Unison 的权限,那么这些工具将更适合此任务。否则,你将不得不编写一些可怕的脚本...


请注意,跟踪是很容易自动化的。假设您想要跟踪来自起源的所有分支。在bash中:git branch -r | grep "^ *origin[^ ]*$" | while read remote_branch; do branch=${remote_branch#*/}; git branch --track $branch $remote_branch; done - Cascabel
@Jefromi:这基本上就是 git remote add --mirror 命令所做的事情 :) - Kent Fredric

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接