“git push --mirror”是否足以备份我的代码库?

74

我是一位独立开发者,使用本地Git仓库进行开发。为了备份,我希望将该仓库的完全副本发送到另一个服务器。

这样做就足够了吗?

git push --mirror

我之所以问这个问题是因为有时候我会运行这个命令两到三次,直到Git告诉我“Everything up-to-date”,所以显然它不是一个完全的镜像。似乎在重新推送跟踪分支...?

$ git push --mirror
Counting objects: 42, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (30/30), done.
Writing objects: 100% (30/30), 5.09 KiB, done.
Total 30 (delta 17), reused 0 (delta 0)
To ssh://my/repo/url
   c094a10..0eedc92  mybranch -> mybranch
$ git push --mirror
Total 0 (delta 0), reused 0 (delta 0)
To ssh://my/repo/url
   c094a10..0eedc92  origin/mybranch -> origin/mybranch
$ git push --mirror
Everything up-to-date

发生了什么事情,这是一个好策略吗?

编辑:我不想使用像git bundle.tar.bz2这样的东西,因为我希望备份是一个可访问的工作副本。由于我的备份服务器连接到网络并始终处于开启状态,这是我在旅途中访问存储库的一种好方法。


2
参见:备份本地Git仓库 - miku
这个备份是否也包括了 reflog?如果不包括的话,那么这个备份就相当糟糕。 - onionjake
8个回答

48
第二次看到被推送的内容是因为--mirror比您预期的要推送得多一些。除了本地分支外,它还会推送您的远程分支,因为镜像意味着所有内容。因此,当您正常推送(或使用--mirror)时,mybranch被推送并且origin/mybranch更新以反映原点上的新状态。当您使用--mirror推送时,origin/mybranch也会被推送。

这导致您看到的奇怪情况,而且当您从该远程拉取时会出现更糟糕的奇怪情况;您将得到名为origin/origin/mybranch等的分支。因此,通常最好只针对一次性复制使用--mirror,并在普通用途中只使用正常的推送(可能带有--all)。

要始终推送所有分支和标签,可以像下面这样更新.git/config

[remote "origin"]
  url = ...
  fetch = ...
  push = +refs/heads/*
  push = +refs/tags/*

这将使普通推送类似于镜像,但它不会删除源端不存在的分支或者对于非快进式更新。


1
谢谢,这很有用。我记得曾经看到过这些origin/origin/*分支,但显然我已经删除了它们。使用--all的问题在于它不会推送任何新分支,也不会删除任何已删除的分支。这不够完美,而我有时可能会犯傻。没有办法告诉--mirror忽略远程分支吗? - Thomas
我认为没有办法让它忽略远程。但是,你可以修改你的.git/config文件以默认推送更多内容。我已更新答案。 - Jakob Borg
“--mirror也会推送您的远程分支”。这仅适用于您已经获取/跟踪的远程分支,对吗?例如,如果您刚刚执行了git clone,则只有master分支,因此git push --mirror将仅镜像master分支,而不是其他任何远程分支。 - wisbucky

29

很遗憾,使用push操作时您无法获得完全相同的副本。您会失去您的存储


5
谢谢,知道这些很好。不过,这并不重要,因为储物箱本来就是一个非常短期的东西。 - Thomas
2
是的,我认为这对于备份来说已经足够好了,但对于同步来说并不理想。此外,我们都知道有时候我们会依赖本应短期的事物很长时间。 ;) - nschum
8
如果您在保留代码存档时需要较长一段时间,或许需要更加熟悉如何创建分支。(: - Jay

15

我认为这是一个完全可接受的备份代码库的策略。它会将存储库中的每个引用都推送到您的远程源。使其成为本地存储库的完整“镜像”。

编辑:我刚看到您在问题中更新的描述。似乎 git 正在将您的远程引用以及其他所有内容推送到远程服务器。一旦推送完成,远程引用将会被更新,以反映您刚刚对其进行了推送操作。此时,它已经过时了,需要进一步的推送。如果您对此不满意,可以使用以下命令删除此远程引用:

git push :origin/mybranch

然后使用以下命令:

git push --all

请记住,这不会推送您创建的任何新分支。


那为什么我第二次运行它时它会执行某些操作呢? - Thomas
“something”是什么意思?你要推送的存储库是裸克隆吗?你能提供更多细节吗?我相信git push --mirror应该提供你正在寻找的功能。 - Greg Sexton
7
值得一提的是,使用 --mirror 选项克隆存储库,然后使用 'git remote add --mirror <name> <url>' 命令。这将自动进行镜像映射,因此您只需运行 'git push' 即可。 - Greg Sexton

8
我所做的是:
设置repo: git clone --mirror user@server:/url-to-repo.git 然后,当你想要刷新备份时: 从克隆位置运行git remote update 这将备份所有分支,包括稍后添加的新分支,但值得注意的是,从克隆中删除的分支不会被删除(对于备份来说可能是一件好事)。
摘自http://www.garron.me/en/bits/backup-git-bare-repo.html

4

我通常使用git push --all。只有当我需要推送新创建的分支或者我删除了一些分支,并且不想一个一个地命名它们时,才会使用--mirror。否则,push --all通常可以满足我的需求。


1

0

我已经花了很长时间尝试开发一个Bash脚本,以安全地备份一组存储库从一个Git服务器到另一个Git服务器。

我相信以下脚本可以正常工作,但建议进行测试。

问题陈述:有一组托管在名为origin的服务器上的存储库。需要定期将所有存储库备份到另一个主机(称为upstream),并获取所有分支。

解决方案:

declare -a projects=("rep1 rep2 rep3 rep4")

for project in ${projects}; do
    cd $project;
    pwd;
    git fetch --all -v;
    git status -v;
    for remote in `git branch -r | grep origin | grep -v /HEAD`; do
        echo Remote $remote; 
        git checkout --track $remote ; 
    done;
    for remote in `git for-each-ref --format '%(refname:short)' refs/heads/`; do
        echo Branch $remote;
        git checkout $remote;
        git pull;
    done
    git push -v --all upstream;
    cd ..;
done

在这个解决方案中,脚本循环遍历所有项目,并针对每个项目执行两个其他循环。在第一个循环中,脚本识别并开始跟踪主机(origin)中的所有分支,甚至是尚未被跟踪的分支。在第二个循环中,脚本拉取所有分支。最后,脚本将所有分支推送到新的 Git 主机(upstream)。

-3
为什么不只是压缩一个 .git 文件夹的副本并将其发送到另一台服务器?

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