关于GitHub:Git-将代码推送到两个远程

Git - Pushing code to two remotes

本问题已经有最佳答案,请猛点这里访问。

我有两个远程Git存储库。origingithub

我把我的分支devel推到两个存储库。

1
2
git push -u origin devel
git push -u github devel

但当我这样做的时候。git push只能推到github上。

我是否可以设置我的两个远程设备,以便用一个命令将更改推送到两个存储库?

  • 另请参见pro-git:9.5 git内部结构-参考规范-推送参考规范。
  • 我投票决定重新讨论这个问题。它不是"关闭原因"中引用的副本。这一个专门询问如何推动多个回购。虽然另一个问题同时提到拉和推,但公认的答案并不包括推到多个回购——尽管如此,一个可以改进它。
  • 我的用例特别需要这样做:我只将它推送到两个存储库,但只从其中一个存储库中提取。所以,如果我只是把问题的答案联系起来,我就无法解决我的问题。


在Git的最新版本中,可以为给定的远程设备添加多个pushurl。使用以下命令将两个pushurl添加到您的origin中:

1
2
git remote set-url --add --push origin git://original/repo.git
git remote set-url --add --push origin git://another/repo.git

因此,当您推到origin时,它将推送到两个存储库。

update 1:git 1.8.0.1 and 1.8.1(以及可能的其他版本)似乎有一个bug,导致--add在第一次使用时替换原始URL,因此需要使用相同的命令重新添加原始URL。执行git remote -v应该显示每个远程的当前URL。

更新2:Git维护人员JunioC.Hamano解释了它是如何设计的。执行git remote set-url --add --push 会为给定的远程添加一个pushurl,它会覆盖推送的默认URL。但是,您可以为一个给定的远程添加多个pushurl,然后允许您使用一个git push推送到多个远程。您可以在下面验证此行为:

1
2
3
4
5
6
7
$ git clone git://original/repo.git
$ git remote -v
origin  git://original/repo.git (fetch)
origin  git://original/repo.git (push)
$ git config -l | grep '^remote\.'
remote.origin.url=git://original/repo.git
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*

现在,如果您想使用一个命令推送到两个或多个存储库,您可以创建一个新的名为all(正如@adam nelson在comments中所建议的那样),或者继续使用origin,尽管后者的名称对此目的的描述较少。如果您仍想使用origin,请跳过以下步骤,在所有其他步骤中使用origin而不是all

因此,让我们添加一个新的名为all的远程程序,稍后我们将在推送到多个存储库时参考它:

1
2
3
4
5
6
7
8
9
$ git remote add all git://original/repo.git
$ git remote -v
all git://original/repo.git (fetch)               <-- ADDED
all git://original/repo.git (push)                <-- ADDED
origin  git://original/repo.git (fetch)
origin  git://original/repo.git (push)
$ git config -l | grep '^remote\.all'
remote.all.url=git://original/repo.git            <-- ADDED
remote.all.fetch=+refs/heads/*:refs/remotes/all/* <-- ADDED

然后,我们将一个pushurl添加到all远程,指向另一个存储库:

1
2
3
4
5
6
7
8
9
10
$ git remote set-url --add --push all git://another/repo.git
$ git remote -v
all git://original/repo.git (fetch)
all git://another/repo.git (push)                 <-- CHANGED
origin  git://original/repo.git (fetch)
origin  git://original/repo.git (push)
$ git config -l | grep '^remote\.all'
remote.all.url=git://original/repo.git
remote.all.fetch=+refs/heads/*:refs/remotes/all/*
remote.all.pushurl=git://another/repo.git         <-- ADDED

这里,git remote -v显示新的pushurl进行推送,所以如果你进行git push all master操作,它只会将master分支推到git://another/repo.git上。这显示了pushurl如何覆盖默认URL(remote.all.url)。

现在,让我们添加另一个指向原始存储库的pushurl

1
2
3
4
5
6
7
8
9
10
11
12
$ git remote set-url --add --push all git://original/repo.git
$ git remote -v
all git://original/repo.git (fetch)
all git://another/repo.git (push)
all git://original/repo.git (push)                <-- ADDED
origin  git://original/repo.git (fetch)
origin  git://original/repo.git (push)
$ git config -l | grep '^remote\.all'
remote.all.url=git://original/repo.git
remote.all.fetch=+refs/heads/*:refs/remotes/all/*
remote.all.pushurl=git://another/repo.git
remote.all.pushurl=git://original/repo.git        <-- ADDED

你看,我们添加的两个pushurl都保留了。现在,一个单一的git push all master将把master分支推到git://another/repo.gitgit://original/repo.git上。

  • 当我使用git push origin时,它现在只会推到git://another/repo.git。现在不推到原始原点。
  • 看起来像个虫子。Git替换了原始的URL,但是用相同的命令重新添加原始的URL应该可以使其正常工作。git remote -v应该显示所有远程的实际URL。如果可行,请通知我,以便我可以相应地更新我的答案。
  • 是的,那很管用。谢谢你的回答。
  • 看来江户十一〔二〕可能更理智。这样,您仍然可以推到上游和源站,但"全部"是一个特殊的遥控器,用于两个遥控器。
  • 这太疯狂了。为什么会有人想要这样的功能?首先添加主控形状,然后用备份覆盖主控形状,然后再次添加主控形状?疯狂的裤子不重写动词的教训。--add表示增加,不是替换。
  • @AJB:实际上是添加了一个新的pushURL。让我们困惑的是,有了pushurl,默认的url就不再用于push了——这一点我完全不同意。
  • @阿达姆尼尔森哦,我同意!刚刚更新了答案以包含您的建议。谢谢您!-)
  • 我有一个问题,我推的2个回购有不同的代理设置。所以当我为远程定义了代理时,它将失败,因为在我的单个远程中现在有2个push repos。有什么建议吗?
  • @当然-见stackoverflow.com/a/35456245/298054-如果它不起作用请告诉我。
  • 非常感谢你。
  • 令人敬畏的向导。我用它来设置2个push URL,因为我想将代码推送到2个不同的来源。
  • 我目前运行的是git版本2.15.1,直到我省略了--add标志,这个版本才对我起作用。然后,它似乎克服了任何错误,一旦在我的配置中出现了一个push-url,我就可以使用上面的命令来满足我的心愿(使用--add--push)。
  • 如何再次删除其中一个?
  • 嗨@jweyrich,我尝试了所有设置,但我仍然只能推动第一次回购。第二次我得到错误:![拒绝]master->master(先获取)错误:未能将某些引用推送到"git@gitlab.com"
  • @罗克萨娜,你想推-f(或-force)吗?看起来第二个repo有一个受保护的分支,它拒绝覆盖历史记录或现有提交。
  • 多谢@jweyrich,你说得对。第二次回购有额外承诺。


要使用一个命令同时发送到两个远程,可以为其创建别名:

1
git config alias.pushall '!git push origin devel && git push github devel'

这样,当您使用命令git pushall时,它将更新两个存储库。

  • 是否仍要使分支成为该命令中的参数?
  • 您可以使用bash函数传递:git config alias.pushall '!f() { git push origin $1 && git push github $1; }; f'
  • 尽管这很管用,但还是有点老土。这似乎是更好的解决方案。
  • 优点:更容易携带;缺点:不适用于--tags,可扩展性较差(比如4个repos)
  • 如果您将不同的项目推到不同的位置,那么多个项目的一个别名就不能很好地工作。
  • @williamsetimizuta用您的命令我得到"语法错误:";"意外"。
  • 我不得不手动编辑.git/config并在[alias]部分中写入pushall ="!git push origin $1; git push github $1 #"#忽略了这条线的其余部分。