如何处理多个遥控器和分支机构

时间:2015-11-06 16:18:00

标签: git git-push git-pull git-remote mirroring

我希望有多个远程服务器,它们应该为所有分支互相镜像。

开始这次冒险,我发现: pull/push from multiple remote locations

告诉我:

$ git remote set-url origin --push --add <a remote>
$ git remote set-url origin --push --add <another remote>

如果我做了

$ git pull --all
Fetching origin
Fetching willi

看起来不错!

但推动不起作用:

$ git push --all
To ssh://gitmini@localhost/home/gitmini/gitrepos/repo1
f974ce2..c146f0a  master -> master

没有推到我的第二个遥控器!为什么呢?

所以,如果我尝试不同的方法,如:

$ git remote add mirroring ssh://gitmini@localhost/home/gitmini/gitrepos/repo2
$ git remote set-url mirroring --push --add ssh://gitmini@localhost/home/gitmini/gitrepos/repo1
$ git remote -vv
mirroring   ssh://gitmini@localhost/home/gitmini/gitrepos/repo2 (fetch)
mirroring   ssh://gitmini@localhost/home/gitmini/gitrepos/repo1 (push)

这真的不是我的期望!

还有一个选项--mirror=fetch|pull,但这也会导致错误配置的结果。

如某些评论所述,如果重复命令,可以添加网址。但我永远不能添加一个以上的回购。作为例子,我可以去看看这个结果,对我来说这似乎充满了错误:

 $ git remote -vv
 mirroring  ssh://gitmini@localhost/home/gitmini/gitrepos/repo1 (fetch)
 mirroring  ssh://gitmini@localhost/home/gitmini/gitrepos/repo2 (push)
 mirroring  ssh://gitmini@localhost/home/gitmini/gitrepos/repo1 (push)
 mirroring  ssh://gitmini@localhost/home/gitmini/gitrepos/repo2 (push)

下次尝试我跑:

 $ git config -e

并添加了以下部分:

[remote "mirroring"]
    url = ssh://gitmini@localhost/home/gitmini/gitrepos/repo1
    fetch = +refs/heads/*:refs/remotes/mirroring/*
    pushurl = ssh://gitmini@localhost/home/gitmini/gitrepos/repo1
    url = ssh://gitmini@localhost/home/gitmini/gitrepos/repo2
    fetch = +refs/heads/*:refs/remotes/mirroring/*
    pushurl = ssh://gitmini@localhost/home/gitmini/gitrepos/repo2     

但是

$ git remote -vv
mirroring   ssh://gitmini@localhost/home/gitmini/gitrepos/repo1 (fetch)
mirroring   ssh://gitmini@localhost/home/gitmini/gitrepos/repo1 (push)
mirroring   ssh://gitmini@localhost/home/gitmini/gitrepos/repo2 (push)

获取repo2的行只是被忽略了!

实际上,我无法设置配置。我的任务很简单:让两个遥控器同步。

编辑:对torek给出答案的一些评论:

看起来可以设置:

[remote "mirroring"]
    url = ssh://gitmini@localhost/home/gitmini/gitrepos/repo1
    fetch = +refs/heads/*:refs/remotes/mirroring/*
    pushurl = ssh://gitmini@localhost/home/gitmini/gitrepos/repo1
    url = ssh://gitmini@localhost/home/gitmini/gitrepos/repo2
    fetch = +refs/heads/*:refs/remotes/mirroring/*
    pushurl = ssh://gitmini@localhost/home/gitmini/gitrepos/repo2

使用此配置

$ git push mirroring 
...
To ssh://gitmini@localhost/home/gitmini/gitrepos/repo1
...
To ssh://gitmini@localhost/home/gitmini/gitrepos/repo2

导致推动两个遥控器。

我不知道这个配置是否有效。

Torek写道:

  

如果您配置了多个,只有其中一个可以使用,其他所有都会被忽略。

似乎不是真的。在我给定的配置中,所有遥控器都将通过推拉来访问,如上面的示例所示。

事实上,使用[remotes]配置的组看起来对我的用例非常有用!

1 个答案:

答案 0 :(得分:2)

遥控器和取件

Git可以有很多&#34;远程&#34; s,所以当你git config -e时,你会看到类似这样的内容:

[remote "r1"]
    url = ...
    fetch = +refs/heads/*:refs/remotes/r1/*
[remote "r2"]
    url = ...
    fetch = +refs/heads/*:refs/remotes/r2/*

但是,任何一个遥控器只能有一个 url(最多只有一个pushurl)。如果配置多个,则只有其中一个可以工作,其他所有都会被忽略。

(有点奇怪,任何一个遥控器都可以有很多fetch个条目,并且所有条目都被遵守。此外,你可以在这里设置push =设置来设置默认的push refspec,尽管我从未使用过我自己。)

当您运行git fetch时,您可以命名一个特定的遥控器:

$ git fetch r1
[fetches from r1]
$ git fetch r2
[fetches from r2]

或使用--multiple命名多个遥控器:

$ git fetch --multiple r1 r2
[fetches from r1 and r2]

所有遥控器:

$ git fetch --all
[fetches from r1, r2, and any other defined remote]

或来自&#34;群组&#34;,我将在稍后定义。 --multiple标志使git fetch将其所有参数视为远程或组名。否则,远程名称后的每个参数都被视为refspec(例如,git fetch r1 r2,而不是--all,意味着从远程r2获取引用r1

A&#34; group&#34;是用例如:

定义的东西
[remotes]
    somegroup = r1 r2

在左侧列出组,在右侧列出遥控器组。请注意,这是远程 s ,复数,您可以使用git config remotes.somegroup r1 r2进行设置,但是当事情变得复杂时,我更喜欢使用git config -e和我的编辑器,以便我可以一起看到一切。

使用此设置,您可以运行git fetch somegroup,它将从r1r2获取。

您还可以运行git remote update,默认为从所有遥控器中提取,但可以配置(通过remotes.groups项目和remotes.default)从特定组或单个提取远程

使用git push时,您只能推送到一个遥控器。要推送到多个遥控器,您必须运行多个git push es。

git push --all并不意味着推送所有遥控器,而是推送所有参考号,就好像您已将refs/*:refs/*作为refspec一样。)

Refspecs,或者获取或推送的内容

fetchpush都使用&#34; refspecs&#34;确定如何开展工作。

完整的refspec看起来就像你在遥控器下的fetch =行中看到的那样,例如:

+refs/heads/*:refs/remotes/r1/*

有一个可选的前导+符号,用于设置强制标记(可以使用--force设置相同的标记),然后是两个引用(例如refs/heads/master或{{1 }}由冒号refs/tags/v1.1字符分隔。可能会出现一个星号:,它有点像shell globbing,除了它在 right 一侧时,它意味着&#34;使用左边的那个方匹配&#34;。 (它也不能出现在任意位置;通常你想在*之后,/refs/heads/*

fetch和push命令不是完全对称的。在执行refs/*时,左侧的名称或模式用于远程的引用,右侧的名称是必要的 1 ,因为它告诉git如何重新确定本地存储库的名称。这就是远程fetch的获取行在右侧读取origin的原因,例如:我们想要重新塑造所有refs/remotes/origin/*引用 - 所有分支 - 成为我们的远程跟踪refs/heads/*中的分支,并置于refs/remotes/下。

但是,对于origin/左侧上的名称或模式是您自己的引用 - 您的分支,标签,备注或其他 - 以及上的名称对适用于遥控器。如果省略右侧名称,通常意味着&#34;在遥控器上使用相同的名称&#34;。因此,git push(无加号且无冒号)表示&#34;将我的分支refs/heads/master推送到远程master&#34;。

(我认为 - 我的意见 - 不是技术要求 - 它是最好的,在定义refspecs推送的配置文件中,你使用冒号并明确左右两侧,即使你可以省略右侧。)

镜像

&#34;镜像&#34;在git中有一个特定的含义,虽然事实证明它有两个不同的含义(master镜像与fetch镜像)。具体含义只是简单地设置fetch或pull refspec来复制所有引用&#34;。例如:

push

导致git放置:

$ git remote add --mirror=fetch foo ssh://foo.foo/foo/foo.git

进入配置文件。 (奇怪的是,这不会在此配置下设置[remote "foo"] url = ssh://foo.foo/foo/foo.git fetch = +refs/*:refs/* 。可能应该这样做,但您可以运行prune = truegit remote update foo --prune来获得相同的效果。)或者:

git fetch -p foo

配置:

$ git remote add --mirror=push foo ssh://foo.foo/foo/foo.git

(参见[remote "foo"] url = ssh://foo.foo/foo/foo.git mirror = true 文档)。

请注意,对多个遥控器进行mirror = fetch是没有意义的。例如,假设您为遥控器git pushr1设置了此项。当您从远程r2作为提取镜像提取时,您将清除所有分支和标记,并使用r1中的分支和标记替换它们。然后,您从r1作为提取镜像进行提取,清除从r2复制的所有分支和标记,并使用r1中的分支和标记替换它们。在这种情况下r2 fetch做了什么好事?

1 如果省略右侧,r1根本无法更新任何参考文献。这将是完全无用的,除了fetch脚本仍然使用的历史模式,其中获取的引用存储在pull文件中。