Git:你能从遥控器的“--push”URL 拉取吗?

Git: can you pull from the "--push" URL of your remote?

为了避免过多的网络流量并加快用户的 git 操作,我们设置了只读 git 镜像,如下所示:

$> git remote -v
origin ssh://git@local.mirror.company.com/repo.git (fetch)
origin ssh://git@central.server.over.slownetwork.company.com/repo.git (push)

而且效果非常好。

然而,要推送,您的本地存储库必须是最新的,并且从中央服务器到本地镜像的镜像延迟可能意味着尽管做了 git pull 您不是最新的与中央服务器。即使镜像延迟只有 12 秒,如果有人在错误的时间尝试 git pull && git push,他们也会非常沮丧。

问题: 如果他们能git pull --pull-from-push-url 问题就基本解决了。有什么方法可以实现吗?

(是的,你可以 运行 git fetch <url of --push server> 但我认为这实际上没有帮助。我认为它不会得到你的提交 merged/rebased 或您的 remotes/origin/<branch> ref 已更新或其他内容。)

更新

根据@jthill 的回复,我在脚本的fetch 部分实现了以下内容,只获取当前分支以提高速度,并考虑到没有推送的遥控器的情况url.

git fetch "$(git config remote.origin.pushurl || git config remote.origin.url)" \
          "$(git rev-parse --symbolic-full-name --abbrev-ref @{upstream}  |
              sed -r -e 's=^origin/(.*)=+refs/heads/:refs/remotes/origin/=')"

您可以将中央仓库和镜像设置为两个单独的远程仓库,然后将一个用于分支的 remote 设置,另一个用于 pushRemote 设置。

这是 .git/config 中的样子:

[remote "mirror"]
    url = git@mirror.example:repo/
    fetch = +refs/heads/*:refs/remotes/mirror/*
[remote "central"]
    url = git@central.example:repo/
    fetch = +refs/heads/*:refs/remotes/central/*
[branch "master"]
    remote = origin
    pushRemote = origin-central
    merge = refs/heads/master`

这样,如果由于镜像上的分支指针已过时而导致冲突,您始终可以从中央服务器获取并将您的提交重新设置为中央服务器分支的基础。

您甚至可以设置两个遥控器来更新共同的远程跟踪分支指针:

[remote "mirror"]
    url = git@mirror.example:repo/
    fetch = refs/heads/*:refs/remotes/origin/*
    fetch = +refs/heads/*:refs/remotes/mirror/*
[remote "central"]
    url = git@central.example:repo/
    fetch = +refs/heads/*:refs/remotes/origin/*
    fetch = +refs/heads/*:refs/remotes/central/*

镜像设置中省略了 + 前缀,以防止从过时的镜像中提取数据向后更新分支指针(即非快进更新)。

必须为每个分支分别设置pushRemote设置。另一种混合解决方案是设置中央遥控器以更新与镜像遥控器相同的远程跟踪分支指针:

[remote "origin"]
    url = git@mirror.example:repo/
    pushurl = git@central.example:repo/
    fetch = refs/heads/*:refs/remotes/origin/*
[remote "origin-central"]
    url = git@central.example:repo/
    fetch = +refs/heads/*:refs/remotes/origin/*

这避免了为每个分支设置 pushRemote

是的,你可以做到。 Fetch 使用“refspecs”,指定要发送的源提交(通常由 refname 模式标识)和(可选但通常)给它们的目标 refnames。

普通克隆的出厂默认参考规范是

+refs/heads/*:refs/remotes/origin/*

这意味着我们还没有源提交,源中的 refnames 标识为 refs/heads/ 名称被获取,并给定目标名称标识为 refs/remotes/origin/ 名称; + 意味着你不关心更新目标引用是否会放弃历史记录(因为这些是远程跟踪引用)。

现在,事情是这样的:遥控器只是一种便利,它们是一种记住您喜欢如何进行提取和推送的方式,git pull 只是一种方便您做自己喜欢做的​​事情抓取后

远程和配置选项等不能反映底层机器作为选项的所有可能用途,抽象非常适合照亮和组织您对领土的看法,但它们是路灯。他们无法涵盖所有​​内容。 Git 方法是提供便利来自动化通常的情况,select 它们的选项,以及填写通常细节的配置项;对于极端情况,即奇怪的情况,您只需直接使用核心命令——这就是便捷命令所做的。它们都是从 shell 调用核心命令的脚本开始的,并且仍然可以以这种方式实现,它们只是有点慢(有时难以察觉)。

git fetch    # get up to date with the local mirror
git fetch $( # get up to date with the real remote
        git config remote.origin.pushurl) $(
        git config remote.origin.fetch)
git merge  # or git rebase, whatever it is you like to do after fetching