git clone --mirror和git clone --bare有什么区别?

677

git clone命令的帮助页面对于--mirror选项的解释如下:

设置远程仓库的镜像。这意味着使用--bare选项。

但是该介绍没有详细说明--mirror克隆与--bare克隆有何不同。


9
有帮助,但如果您还想将此镜像推送到像GitHub这样的远程仓库,我发现这个链接很方便:https://help.github.com/articles/duplicating-a-repository#mirroring-a-repository。 - Eat at Joes
9个回答

768
区别在于使用--mirror时,所有引用都会按原样复制。这意味着包括远程跟踪分支、注释、refs/originals/*(来自filter-branch的备份)等所有内容都会被复制到克隆仓库中。它也被设置为远程更新将从源重新获取所有内容(覆盖已复制的引用)。其实这个想法就是要镜像存储库,以便完全复制,例如可以在多个地方托管中央存储库或对其进行备份。可以将其视为直接复制存储库,只不过是以更加优雅的Git方式。
新的文档几乎涵盖了所有内容:

--mirror

设置源存储库的镜像。这意味着--bare。与--bare相比,--mirror不仅将源的本地分支映射到目标的本地分支,还将所有引用(包括远程分支、注释等)映射并设置refspec配置,以使所有这些引用都被目标存储库中的git remote update覆盖。

我的原始答案还指出了裸克隆和普通(非裸)克隆之间的区别-非裸克隆设置远程跟踪分支,仅为HEAD创建本地分支,而裸克隆直接复制分支。
假设源存储库有几个分支(master(HEAD)nextpumaint)、一些标签(v1v2v3)、一些远程分支(devA/masterdevB/master)和一些其他引用(refs/foo/barrefs/foo/baz,可能是注释、存储、其他开发人员的命名空间等)。
  • git clone origin-url(非裸仓库):你会得到所有的标签,一个本地分支master(HEAD)跟踪远程分支origin/master,以及远程分支origin/nextorigin/puorigin/maint。这些跟踪分支被设置为如果你执行像git fetch origin这样的操作,它们将按照你的期望进行获取。任何远程分支(在克隆的远程中)和其他引用都将完全被忽略。

  • git clone --bare origin-url你会得到所有的标签,本地分支master(HEAD)nextpumaint,没有远程跟踪分支。也就是说,所有分支都按原样复制,并且完全独立设置,不需要再次获取。任何远程分支(在克隆的远程中)和其他引用都将完全被忽略。

  • git clone --mirror origin-url每一个引用都将按原样复制。你将得到所有的标签,本地分支master(HEAD)nextpumaint,远程分支devA/masterdevB/master,其他引用refs/foo/barrefs/foo/baz。所有东西都与克隆的远程完全一样。远程跟踪被设置为如果你运行git remote update,所有引用将从origin覆盖,就像你刚刚删除了镜像并重新克隆它一样。正如文档最初所说的那样,这是一个镜像。它应该是一个功能上完全相同的副本,可以与原始版本交换。


3
“Normal clone” 是否指没有使用 --bare 或 --mirror 标志的克隆? - Sam
3
是的,就像 man 手册上所说的那样,在克隆时使用 bare 参数会直接复制分支(没有 refs/remotes/origin,没有跟踪)。已编辑。 - Cascabel
4
你能否增加一些更多的用法示例来说明差异,而不仅仅是git内部的差异? - cmcginty
1
@SubratoPatnaik,你将获得你正在克隆的存储库中的所有内容。如果他们已经将所有分支都推送到其中,你将获得它们;如果他们没有这样做,你就不会获得。如果你直接克隆他们的本地存储库,你将获得其中的所有内容。 - Cascabel
1
不错的回答。那子模块呢?它们算作“其他引用”吗? - Adam J Richardson
显示剩余9条评论

95
$ git clone --mirror $URL

是一个简写形式

$ git clone --bare $URL
$ (cd $(basename $URL) && git remote add --mirror=fetch origin $URL)

以下翻译内容直接从这里复制而来:

当前手册是这样描述的:

--mirror 不仅会映射源仓库的本地分支到目标仓库的本地分支,还会映射所有引用(包括远程分支、注释等),并设置一个 refspec 配置,以便在目标仓库中通过 git remote update 命令覆盖所有这些引用。


8
我认为你需要在此之后进行 git fetch,才能使它与实际内容完全相同。无论如何,这有点不是正面回答问题——问题的重点在于“镜像远程/克隆与普通的有什么不同?” - Cascabel
8
我很喜欢这种展示差异的方式。希望它准确无误!我希望 hfs 添加 fetch 命令。 - joeytwiddle
并不是很清楚,例如 $(basename $URL) 翻译成什么等等。 - Kzqai
6
basename 是一个通常用于Unix的实用工具,它可以剥离路径中的目录部分,而 $() 则是Bash命令替换的简写。 - Victor Zamanian
10
这里仍然包含--mirror。只有在解释了git remote add --mirror的作用后,这才是一个可以接受的答案。 - Zenexer

29

我添加了一张图片,展示了镜像和裸版本之间的config差异。 enter image description here 左边是裸版本,右边是镜像。你可以清楚地看到,镜像的配置文件有fetch键,这意味着你可以通过git remote updategit fetch --all来更新它。


28

我今天用git-2.0.0进行的测试表明,--mirror选项不会复制钩子、配置文件、描述文件、info/exclude文件,以及在我的测试用例中至少有一些引用(我不理解)。我不认为它是一个“功能上与原始版本完全相同、可以互换的副本”。

-bash-3.2$ git --version
git version 2.0.0
-bash-3.2$ git clone --mirror /git/hooks
Cloning into bare repository 'hooks.git'...
done.

-bash-3.2$ diff --brief -r /git/hooks.git hooks.git
Files /git/hooks.git/config and hooks.git/config differ
Files /git/hooks.git/description and hooks.git/description differ
...
Only in hooks.git/hooks: applypatch-msg.sample
...
Only in /git/hooks.git/hooks: post-receive
...
Files /git/hooks.git/info/exclude and hooks.git/info/exclude differ
...
Files /git/hooks.git/packed-refs and hooks.git/packed-refs differ
Only in /git/hooks.git/refs/heads: fake_branch
Only in /git/hooks.git/refs/heads: master
Only in /git/hooks.git/refs: meta

20
以下是关于复制存储库的GitHub文档中的详细说明:

与裸克隆一样,镜像克隆包括所有远程分支和标签,但每次获取时都会覆盖所有本地引用,因此它始终与原始存储库相同。


1
谢谢,这为我澄清了一个问题,即使用镜像克隆将覆盖本地标签以及分支。非常有帮助。 - Wildcard
3
当运行git fetch时,你可能还想使用--prune选项来删除本地不再存在于远程的引用。 - nishanthshanmugham

18

克隆会将远程的引用复制并放入名为“这些是远程拥有的引用”的子目录中。

镜像会将远程引用复制并放入自己的顶层目录中,它会用远程的引用替换自己的引用。

这意味着,当有人从你的镜像拉取并将镜像的引用放入他们的子目录时,他们会得到与原始引用相同的引用。从最新的镜像获取的结果与直接从初始仓库获取的结果相同。


12
与“git clone”不同,“git clone --mirror”和“git clone --bare”都是裸仓库。它们之间的区别在于“config”文件。
“git clone”的“config”文件如下:
[remote "origin"]
    url = https://github.com/example
    fetch = +refs/heads/*:refs/remotes/origin/*

git clone --bare的配置文件如下:

[remote "origin"]
    url = https://github.com/example

git clone --mirror 的配置文件如下:

[remote "origin"]
    url = https://github.com/example
    fetch = +refs/*:refs/*
    mirror = true

因此,我们可以看到在拉取时使用的refspec中的主要区别是:
引用规范的格式如下,首先是可选的+,后面跟着<src>:<dst>,其中<src>是远程端参考的模式,而<dst>是本地跟踪这些参考的位置。如果+前缀出现在引用规范中,则表示不管是否快进,Git 都会更新该引用。
在自动由git remote add origin命令编写的git clone情况下,Git 会获取服务器上refs/heads/下的所有引用,并将它们写入本地的refs/remotes/origin/中。
git clone --bare情况下,没有用于获取的refspec。
git clone --mirror情况下,用于获取的refspec看起来像fetch = +refs/*:refs/*。这意味着将获取tagsremotesreplace(位于refs目录下)以及heads。请注意,默认情况下git clone仅获取heads
注意1:git clone --mirrorgit clone --bare --mirror是等价的。
注意2:还有packed-refs方面的差异。由于它以更有效的方式记录与refs/headsrefs/tags/和相关信息相同。

关于配置差异的重要细节,@Cascabel 没有指出。 - Andry

9
$ git clone --bare https://github.com/example

该命令将使新的“example”目录本身成为$GIT_DIR(而不是example/.git)。此外,远程分支头将直接复制到相应的本地分支头,而无需映射。当使用此选项时,既不会创建remote-tracking分支,也不会创建相关的配置变量。
$ git clone --mirror https://github.com/example

与裸克隆类似,镜像克隆将包含所有远程分支和标签,但是每次获取时,它都将覆盖所有本地引用(包括远程跟踪分支,注释等),因此它始终与原始存储库相同。

0
与裸克隆一样,镜像克隆包含所有远程分支和标签,但每次获取时,所有本地引用都将被覆盖,因此它将始终与原始仓库相同。设置推送的URL可以简化向镜像仓库推送的过程。
参考链接:复制仓库

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