我该如何从多个远程位置拉取/推送代码?

864

简述: 是否有一种方法可以让 git 仓库推送和拉取多个远程仓库的列表(而不是单个的“origin”)?

详述: 我经常遇到这样的情况:在多台电脑上开发应用程序,网络连接方式也不同——比如在运输中使用笔记本电脑,在某个位置使用计算机“A”,在另一个位置使用计算机“B”。此外,笔记本电脑可能只与“A”或“B”之一连接,并且有时两者都连接。

我想做的是让 git 总是从它当前可以连接到的所有电脑上 “pull” 并 “push”,这样更容易从一台机器跳转到另一台机器并继续无缝工作。


49
对于新访客的说明(截至2016年):目前正确的方法是使用一流的git功能,包含在malvineous的下面的答案中,被认可的答案是不正确的。 - ELLIOTTCABLE
我发现提供在此处的答案非常详细和概括。 - Gangula
17个回答

4
我把 nona-urbiz 的这个答案进行了扩展,你只需要将以下内容添加到你的 ~/.bashrc 文件中:
git-pullall () { for RMT in $(git remote); do git pull -v $RMT $1; done; }    
alias git-pullall=git-pullall

git-pushall () { for RMT in $(git remote); do git push -v $RMT $1; done; }
alias git-pushall=git-pushall

使用方法:

git-pullall master

git-pushall master ## or
git-pushall

如果在git-pullall中没有提供任何分支参数,则从非默认远程仓库拉取将会失败;保留这种行为,因为它类似于git。

4

更新远程仓库(即pull的情况)变得更加容易了。

Linus在引用条目中说:

不幸的是,甚至没有任何方法可以通过git别名来伪造它。

这段话在Git邮件列表中的引用已经不再适用,详情请参考elliottcable的回答

git fetch在过去学会了--all参数,允许一次性获取所有远程仓库。

如果不需要全部请求,则可以使用--multiple开关来指定多个远程仓库或一个组。


+1 对于*--多个* :) 正是我在寻找的东西。通常我有多个遥控器,知道哪些是可达的,哪些是不可达的。有了这个,我可以明确列出我想要获取的位置。谢谢。 - undefined

3

您需要编写一个脚本来循环处理它们。Git没有提供“全部推送”的功能。理论上,您可以在多个线程中进行推送,但没有本地方法可用。

Fetch更加复杂,我建议按顺序执行。

我认为最好的答案是有一台机器,每个人都可以推送/拉取,如果可能的话。


3
问题是,正如我所描述的那样,没有始终可用的中央主机。如果我必须编写一个循环Bash脚本,那就这样吧,但分布式版本控制在这里似乎不能为我提供更多帮助... - Zorzella
2
由于分布式的特性,它假设并非所有人都可用或希望被推送。它还涉及到不同的存储库处于不同的状态,并且假设其他人正在同时处理它们。您从一组存储库中推送和拉取的顺序会影响不同存储库的状态,您需要进行多次操作才能使它们真正同步。这就是为什么没有“全部拉取/推送”的原因。然后就会出现冲突... ;) - Jeff Ferland

2

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

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

当你推送到origin时,它将会推送到两个仓库。
更新1:Git 1.8.0.1和1.8.1(以及可能的其他版本)似乎存在一个bug,导致--add在第一次使用时替换原始URL,因此您需要使用相同的命令重新添加原始URL。通过执行git remote -v可以查看每个远程的当前URL。
更新2:Git维护者Junio C. Hamano解释说这是设计上的问题。执行git remote set-url --add --push 为给定的远程添加了一个pushurl,它会覆盖推送的默认URL。但是,您可以为给定的远程添加多个pushurl,然后可以使用单个git push将其推送到多个远程。您可以在下面验证此行为:
$ 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),或者继续使用 origin,尽管后者对于此目的来说不够描述性。如果你仍想使用 origin,请跳过以下步骤,并在所有其他步骤中使用 origin 而不是 all。
因此,让我们添加一个名为 all 的新远程仓库,以后在推送到多个仓库时将引用它:
$ 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 ,指向另一个代码库:

$ 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,则只会将主分支推送到git://another/repo.git。这展示了pushurl如何覆盖默认的url(remote.all.url)。

现在让我们添加另一个指向原始仓库的pushurl:

$ 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

我们添加的两个pushurls都被保留。现在,使用单个git push all master命令,就可以将主分支推送到git://another/repo.git和git://original/repo.git。

重要提示:如果你的远程库有不同的规则(钩子)来接受或拒绝推送,则其中一个远程库可能会接受它,而另一个则不会。因此,如果您希望它们具有完全相同的历史记录,您需要在本地修复提交,使它们可被两个远程库接受并再次推送,否则您可能会面临只能通过重写历史记录(使用push-f)来修复它的情况,并且这可能会对已经从库中拉取了您之前的更改的人造成问题。


2
使用以下命令在全局gitconfig(/home/user/.gitconfig)中添加别名。
git config --global alias.pushall '!f(){ for var in $(git remote show); do echo "pushing to $var"; git push $var; done; }; f'

当你提交代码后,我们会使用

git push

默认将代码推送到远程仓库。在设置别名之后,我们还可以使用

git pushall

来更新所有的远程仓库,包括主仓库。


2
在每个使用的机器上设置all远程有点繁琐。此外,提供的bashgit aliases都假设您将推送到all remotes。(例如:我在GitHub和GitLab上维护一个sshag的fork,我添加了upstream远程,但我没有权限推送到它。)这里是一个gitalias,只会推送URL包含@的远程。
psall    = "!f() { \
    for R in $(git remote -v | awk '/@.*push/ { print $1 }'); do \
    git push $R $1; \
    done \
    }; f"

-3
添加新的远程。
git remote add upstream https://github.com/example-org/example-repo.git

git remote -vv

从多个位置获取表单。
git fetch --all

推到指定位置
git push -u upstream/dev

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