【问题标题】:Unable to fetch from mirror无法从镜像中获取
【发布时间】:2014-08-05 23:02:45
【问题描述】:

我正在将 git 存储库从 Github 迁移到本地 Atlassian Stash 服务器。虽然我正在开发基础设施,但开发人员仍在与 Github 合作,我的目的是将他们的工作从 Github 镜像到 Stash,直到我使用 Stash。

无论如何,我将我的本地镜像设置如下:

git clone --mirror https://github.com/myorg/myrepo.git myrepo-mirror
cd myrepo-mirror
git remote set-url --push origin nowhere.com # prevent accidental pushes to origin
git remote add stash https://stash/myproj/myrepo.git # set "stash" remote for pushing

然后我会定期(通过 cron)获取和推送:

git fetch -p origin
git push --mirror stash

但是,它在git fetch 处失败。我收到以下错误:

致命:refs/remotes/origin/master 同时跟踪 refs/heads/master 和 refs/remotes/origin/master 命令流意外结束

我运行git branch -r,它看起来很正常。所以我运行git ls-remote origin,我看到了通常情况,底部有这两个奇怪的(我认为):

 7e438ee97be8c7cbd8012c3c96b60e3ff8cb3c2c       refs/remotes/origin/HEAD
 7e438ee97be8c7cbd8012c3c96b60e3ff8cb3c2c       refs/remotes/origin/master

我认为最后一个是问题,但我不确定,或者如何解决它。我还跑了git config --get-all remote.origin.fetch 看看:

+refs/pull/*/head:refs/remotes/origin/pr/*
+refs/heads/*:refs/remotes/origin/*
+refs/*:refs/*

但同样,我不确定是否或如何解决。

全面披露

我早些时候尝试镜像似乎工作正常,但我在测试时不小心git push --mirror 使用过时的工作副本强制推送源(是的,我知道)。我尝试通过访问我最近获取的 CI 服务器并重新创建所有分支来进行重建,然后将镜像推送回 github 以使一切恢复正常。这可能就是这些奇怪的 ref 问题开始的地方。

一边

我也尝试了git clone --bare url,然后又尝试了git fetch -p origin && git push --mirror stash,它说它正在工作,但我从未在我的 Stash 存储库中看到更新的提交。

【问题讨论】:

  • 你看过.git/config吗?也许你可以在那里改变一些东西并看到错误?如果没有,你也可以看看.git/refs/*。删除那里的内容时要小心。

标签: git version-control mirror


【解决方案1】:

有趣。我很好奇,如果你重复这一步:

git clone --mirror https://github.com/myorg/myrepo.git myrepo-mirror

使用新副本,完成后立即将cd 放入新克隆并重复此操作:

git config --get-all remote.origin.fetch

你会得到相同的三个 refspec 行吗?如果是这样,git clone --mirror 有问题。如果不是,那是其他事情搞砸了。

现在,谈谈问题本身。问题在于这三行fetch

+refs/pull/*/head:refs/remotes/origin/pr/*
+refs/heads/*:refs/remotes/origin/*
+refs/*:refs/*

第一个告诉git fetch,在从origin 获取之后,如果“他们”(远程)有分支refs/pull/master/head,例如,你的git 应该将它重命名为refs/remotes/origin/pr/master+ 表示“强制”,即,即使您已经有一个 refs/remotes/origin/pr/master,也将其替换为新的 refs/pull/master/head SHA-1。

第二个告诉git fetch,在从origin获取之后,如果他们有refs/heads/master,例如,你的git应该把它重命名为refs/remotes/origin/master(这是正常的,非--mirror设置) .和以前一样,设置了“力”;您的 refs/remotes/origin/master 将被新的 SHA-1 覆盖。

第三个告诉git fetch,从origin获取后,如果他们有refs/heads/master,你的git应该用新的SHA-1覆盖你自己的refs/heads/master;如果他们有refs/pull/master/head,你的git应该覆盖你自己的refs/pull/master/head

所以,你运行git fetch,结果天哪,他们确实有一个refs/heads/master。 (真是一个惊喜......不是!)所以你的 git 应该:

  • 重命名为refs/remotes/origin/master
  • 不,等等,将其重命名为refs/heads/master

这就是您的fetch 因错误而停止的地方:它必须只选择这两个中的一个,就像众所周知的驴在两个干草堆之间一样,它只是冻结并死了。1

(如果有 refs/pull/master/head,你的 git 会被告知将其重命名为 refs/remotes/origin/pr/masterrefs/pull/master/head。这也会失败。但 refs/heads/master 失败足以阻止事情。 )

解决方法在于确定您是否需要真正的镜子。如果是这样,请删除除+refs/*:refs/* 之外的所有行。然后,您的 git 将在 git fetchgit remote update 上,将他们所有的 refs/* 引用转换为您自己的具有完全相同名称的引用。 (并添加 --prune 让您的 git 丢弃您身边不再存在的引用。这就是您一直在做的事情,所以我想您真的想要一个真正的镜子。)

(请注意,所有这些都特定于远程origin。如果/当您运行git push --mirror stash 对名为stash 的远程进行镜像式推送时,这完全独立于fetch 的配置远程命名为origin。使用--mirror,您实际上是在将push refspec 设置为+refs/*:refs/*,并自动修剪,所以这很像从您那里远程获取,将远程的配置设置为获取镜像.)


1如果你用一头真正的驴子试试这个,他只会吃掉两个干草堆。这只是表明 git 并不是一个真正的智能......好吧,你知道的。 :-)

【讨论】:

  • 这更有意义。就在您回答之前,我通过git config remote.origin.fetch 'refs/heads/*:refs/heads/*' 更改了获取,从而忽略了/refs/remotes/*,它开始工作。我不确定这是否是最好的fetch 配置,但至少它可以工作。是的,当我在克隆镜像后直接运行git config --get-all 时,我得到相同的三行。我将尝试一些不同的存储库,看看我得到了什么。
  • 使用+refs/heads/*:refs/heads/*,您将获得部分镜像,因为您的 git 将带入所有分支(分支是 refs/heads/ 下的引用),但仅此而已,例如,没有标签 (refs/tags/* )。
猜你喜欢
  • 2023-04-03
  • 2018-11-16
  • 1970-01-01
  • 2021-03-13
  • 1970-01-01
  • 2015-06-28
  • 1970-01-01
  • 2018-02-14
  • 1970-01-01
相关资源
最近更新 更多