使用Git如何将多个远程服务器与所有分支保持同步

3
我有两台电脑,分别存储着我的代码库(repo1和repo2),它们没有通过任何网络连接在一起。我还有一个本地的 “克隆”(clone),可以在这两台电脑之间移动。让我们把这个克隆库叫做“clone”。
如果我从源头 (即 repo1) 获取我的克隆库,一切都很好。但是如果我需要使用 repo2,我无法让它运行!简单地说,命令是:
git fetch --all repo2

给我这样的提示:fetch --all不接受仓库参数。

此时,我不知道该如何继续操作了。

我发现了很多解决方法,比如:如何在Git中克隆所有远程分支?

但是没有一个答案处理多个存储库!

这是否根本无法管理?


这不太清楚 - 你想要将分支推送/拉取到哪里? - Oliver Charlesworth
@OliverCharlesworth:更新以希望搞清楚这个问题。 - Klaus
2个回答

3
首先,建议通过执行git remote -v检查您的存储库URL。接下来,假设您有两个名为originrepo2的远程存储库。
关于您提到的SO问题-如何克隆Git中的所有远程分支?-应该注意的是,不需要检出所有分支来检索它们,因为git fetch repo2足以在本地获取远程repo2的整个历史记录。
根据 git fetch的文档, 您也可以使用git fetch --all(不需要额外的参数)代替git fetch origin; git fetch repo2
我记得要列出与名为repo2的远程对应的远程分支,只需执行git branch -r,它将显示类似于:
origin/HEAD -> origin/master
origin/master
origin/name-of-an-origin-branch
...
repo2/HEAD -> repo2/master
repo2/master
repo2/name-of-a-repo2-branch
...

即,所有远程分支都以远程标识符为前缀。
为了浏览这些远程分支的内容(无需互联网连接),您可以执行gitk --all来显示所有分支历史记录的只读摘要,或者执行git checkout name-of-a-repo2-branch来创建与跟踪分支name-of-a-repo2-branch关联的本地分支(请参阅git checkout文档)。
或者您可以执行通常的Git操作,例如合并(例如,git merge origin/master),变基(例如,git rebase repo2/master),涉及您的远程存储库的跟踪分支。
同步两个存储库的工作流建议。
关于您的主要用例(同步两个没有直接网络连接的仓库,使用“本地可移动克隆”),我认为最简单的配置是在给定的本地URL上拥有一个“裸”的可移动中间仓库(即,一个没有工作目录的仓库,请参见相应文档),例如“file:///path/to/bare-repo.git”。
要设置这样的仓库,您只需执行以下操作:
git init --bare /path/to/bare-repo.git

然后在repo1中,您可以进行以下设置:
git remote add sync file:///path/to/bare-repo.git
git config alias.pull-ff-sync '!f(){ git fetch sync && git for-each-ref --format "%(refname:strip=3)" refs/remotes/sync/ | grep -v -e '\''^HEAD$'\'' | xargs -n1 bash -c '\''git checkout -q "$1" && git pull --ff-only -v sync "$1"'\'' bash; }; f'
git config alias.pull-ff-sync  # to check the alias has been properly setup
# and in particular that the «'\''» have been replaced with single «'»

git config push.default matching

for b in master develop ... ; do git push sync ${b}; done
# push all the branches you want to sync

当然,在repo2中也有类似的设置:

git remote add sync file:///path/that/can/be/different/to/bare-repo.git
git config alias.pull-ff-sync '!f(){ git fetch sync && git for-each-ref --format "%(refname:strip=3)" refs/remotes/sync/ | grep -v -e '\''^HEAD$'\'' | xargs -n1 bash -c '\''git checkout -q "$1" && git pull --ff-only -v sync "$1"'\'' bash; }; f'
git config push.default matching

现在,在repo1(或repo2)中,您可以按以下方式进行同步:
  • to fetch all the branches you have selected and merge them if the operation is fast-forward (so this command is more powerful than just git fetch sync because all local branches will be updated if a manual merge commit is not required):

      git pull-ff-sync
    
  • to push all the branches you have selected (which relies on the matching setting of the push.default configuration):

      git push -v sync
    

避免一个配置步骤的备注

请注意,如果您不想更改两个仓库的push.default配置(例如,如果您还想使用git push仅将repo1的一个分支推送到另一个远程仓库...),您可以选择:

  • replace

      git config push.default matching
    

    with

      git config push.default upstream  # recommended
    

    or just with

      git config push.default simple  # the default config in Git >= 2.0
    
  • run the slightly longer command below to send all matching branches from repo1 (resp. repo2) to the sync remote in one go:

      git push -v sync :
    

我收到了所有的分支,但是我无法推送它们!push --all 命令并不会包含所有其他的分支。这正是我在真正执行之前脑海中存在的误解 :-) - Klaus
@Klaus,这是正常的,因为例如仅使用git push,除非您已设置当前分支的上游远程,否则不会推送任何内容。但是,如果您在本地和repo2远程都有一个master分支,则例如git push repo2 master应该可以工作。如果需要,我可以在我的答案中提供更多关于这个主题的指针。 - ErikMD
是的,如果我知道每个分支,我可以推送每个单独的分支。但是我只想简单地保持两个仓库同步,而不需要手动处理每个分支。 - Klaus
其实我认为你应该要么针对 "git push" 提出一个新问题, 要么编辑你的问题描述清楚你在使用两个远程库的情况下是什么。因为你现在的问题只涉及到 git fetch , 这个我在我的答案中已经讲过了。 - ErikMD
这不是关于推送、获取和拉取的问题...正如标题所说:“保持多个远程服务器同步”。使用案例已经描述:两个PC上的两个仓库。如何使用可移动克隆使它们保持同步。有什么遗漏吗? - Klaus
好的。我认为你的配置不太常见(因为原则上,帮助同步两个仓库的中间仓库(“本地可移动克隆”)应该是一个“裸”仓库,可以从repo1和repo2访问,而似乎你的“可移动克隆”是一个“非裸”仓库,有两个远程IIUC)。无论如何,我认为你需要的只是在repos repo1和repo2中设置推送的特定配置。我将在我的答案中建议这样做。 - ErikMD

0

ErikMD提出的两个方案是正确的。

但是,如果您不介意强制推送仓库,即您已经运行了(git pull --allgit fetch -all),并且确信在执行此操作期间另一台电脑不会提交任何内容,则可以这样做:

git push --mirror

来自文档:

--mirror

不需要为每个要推送的引用命名,而是指定将 refs/(其中包括但不限于 refs/heads/、refs/remotes/ 和 refs/tags/)下的所有引用镜像到远程仓库。新创建的本地引用将被推送到远程端,本地更新的引用将被强制更新到远程端,并且删除的引用将从远程端删除。如果配置选项 remote..mirror 已设置,则这是默认设置。

修复 all 选项的另一种方法是尝试 this answer


我看到这个解决方案有两个问题:(1) 如此处所述,我们不应该在没有使用--mirror克隆的存储库中使用git push --mirror。另请参见这个那个。(2)--mirror特别适用于单向备份,而不是与可能同时发展的两个存储库进行双向同步...更不用说强制推送时丢失历史记录的风险了。 - ErikMD

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