了解"git remote show"命令输出...这意味着: "Local ref configured for 'git push'" ?



我有两个远程和两个本地分支:

  • 本地分支"master"正在跟踪远程分支"origin/master">
  • 本地分支"镜像"正在跟踪远程分支"github/master">

这在我的.git/config文件中:

...
[remote "origin"]
url = http://my.gitlab.com/nandoquintana/repo.git
fetch = +refs/heads/*:refs/remotes/origin/*
[remote "github"]
url = https://github.com/nandoquintana/repo.git
fetch = +refs/heads/*:refs/remotes/github/*
[branch "master"]
remote = origin
merge = refs/heads/master
[branch "mirror"]
remote = github
merge = refs/heads/master
[push]
default = tracking

这是"git remote show origin"的输出:

$ git remote show origin 
* remote origin
Fetch URL: http://my.gitlab.com/nandoquintana/repo.git
Push  URL: http://my.gitlab.com/nandoquintana/repo.git
HEAD branch: master
Remote branch:
master tracked
Local branch configured for 'git pull':
master merges with remote master
Local ref configured for 'git push':
master pushes to master (up to date)
$ git remote show github
* remote github
Fetch URL: https://github.com/nandoquintana/repo.git
Push  URL: https://github.com/nandoquintana/repo.git
HEAD branch: master
Remote branch:
master tracked
Local branch configured for 'git pull':
mirror merges with remote master
Local ref configured for 'git push':
master pushes to master (local out of date)

"推"one_answers"拉"命令都能正常工作:

  • "push"命令将本地分支中提交的编辑发送到"her"远程分支
  • "pull"命令将提交从远程分支带到"her"本地分支

那么,为什么"为‘git push’配置的本地ref"是"master pushs to master"?为什么不"镜像推主"呢?"本地过时"是什么意思?

在@torek回答后更新

以下是参考文献:

$ git ls-remote github
455063a9db09977535ac808af5729181b153f4c7    HEAD
455063a9db09977535ac808af5729181b153f4c7    refs/heads/master
$ cat .git/refs/heads/master
ca9e4399058a4998bd7c993f86d6740cfaec820b
$ cat .git/refs/heads/mirror
455063a9db09977535ac808af5729181b153f4c7
$ cat .git/refs/remotes/github/master
455063a9db09977535ac808af5729181b153f4c7

确切地说,"refs/remotes/github/master"one_answers"refs/heads/master"是不相等的。这就是为什么出现"本地过期"消息的原因:

master pushes to master (local out of date)

这对我来说不是问题,我确实知道"remotes/github/master"和本地"master"中的代码是不同的。

尽管如此,"remotes/github/master"和本地"mirror"中的代码是相同的。事实上,refs"refs/remotes/github/master"one_answers"refs/heads/mirror"是相等的。

这条信息会让我安心:

mirror pushes to master (up to date)

如何配置远程/github。。。或者push.default…来获得这个输出?

[提醒我自己和OP:remoteorigin=GitLab,remotegithub=GitHub。从根本上讲,使用git remote show的主要问题是它做出了的假设。这些假设是关于你将来将如何运行其他Git命令git fetchgit push,以及这些Git命令中涉及的第二个Git存储库将来将如何布局r、 显然,丹麦有句古老的谚语:很难做出预测,尤其是对未来的预测]

让我在这里回答顶部经过编辑的问题:

这条消息会让我安心:

mirror pushes to master (up to date)

如何配置远程/github。。。或者push.default…来获得这个输出?

有一件事值得一试:一个push.default设置upstream告诉Git,默认情况下,git push应该这样做。如果这行得通,做了你想做的事,你就做好了。但请注意,不管Git在这里说什么,这都是一个谎言。

根本问题是mirror没有推送到master在您输入git push命令之前,它根本不会推送任何内容;一旦您输入了该命令,您就可以控制,其中git push命令一起执行,该命令可以完全覆盖git remote show所做的任何声明。

您在git push时间的选择是:

  • 不提供其他参数。

    在这种情况下,您的Git会从当前上游选择远程。如果上行设置为origin/...,则远程为origin。如果上行设置为github/...,则远程为github。它看起来像一个简单的字符串替换(通常是这样,尽管由于历史原因,它实际上是一个非常复杂的字符串替换,通常被证明是简单的:取斜杠之前的部分)。

    在这一点上,你的Git继续到这里列出的第二个案例。

  • 提供一个额外的参数。这个参数命名要连接的另一个Git。它通常是远程(origingithub),不过现在你可以给出一个URL。

  • 提供两个或多个附加参数。这些名称中的第一个是远程(或是URL)。其余为参考规范,定义如下。

此时,你的Git连接到那个远程,实际上,运行git ls-remote来查看它们有哪些分支。这个列表很重要,因为它与您根据push.default设置给出或未给出的refspec一起使用,而且当您给出refspec时,您只能给出一半的refspec。

特别有问题的是"半个refspec"的情况。无论你做什么或设置什么,如果你在mirror上运行git push github mirror,你的Git都会要求远程github上的Git设置。。。好吧,这取决于你是否有一个上行设置,如果没有,你的push.default设置。详细信息在git push文档中,以Git通常的神秘形式。不过,默认默认值是,对于"半参考规范",名称mirror的意思是mirror:mirror

如果你给出一个完整的refspec,例如git push github mirror:asdf,那么refspec的后半部分将决定你的Git要求他们的Git设置哪个分支名称。如果你给出一半refspec,那么你给出的一半通常会变成两个名字。默认值为push.default = simple时,您不能意外地将您的mirror推送给任何其他人的master,您必须使用显式的完整refspec(然后由您决定是否正确)。

如果你给没有refspec,你的Git会回到push.default,并且只有五个设置。默认的simple会让你的Git将你的分支集与他们的分支集(来自git ls-remote)进行比较。如果你的分支,如mirror没有任何相应的分支,你的Git不会要求他们的Git设置任何分支。

假设您在分支mirror上,其上游设置为github/master,并且您已将push.default配置为upstream(使用git config push.default upstream):

  • 如果运行不带参数的git push或不带附加参数的git push github,则远程将为github

  • 如果没有提供refspec,则应用push.default设置:refspec Git将构造为mirror:master

  • 然而,如果你提供了半个refspec,我不确定,即使在重读了几次文档之后,完整的refspec Git会构建什么。我认为它将是mirror:mirror,这不是你想要的。

  • 您还可以配置一个remote.github.push变量,该变量提供默认的refspec。这也可以让你得到你想要的,尽管push.default = upstream看起来更简单。

我们现在回到原来的答案。:-)


那么,为什么"为‘git push’配置的本地ref"是"master pushs to master"?

这意味着:

  • 假设您当前的分支是master(即,您已经运行了git checkout master)
  • 如果随后运行git push github(而不是git push github more-command-words)
  • Git——特别是您自己的Git——将尝试将您当前的master推送到https://github.com/nandoquintana/repo.gitmaster

这可能会成功,也可能不会成功,这取决于GitHub上的Git服务器如何礼貌地请求将master设置为Git通过此推送请求发送的任何哈希ID。

(如果您在master上并运行git push origin,也同样适用,同样没有其他参数,只是名称origin指的是GitLab中的Git。)

另一方面,假设您当前的分支名为mirror:

  • 所以您刚刚运行了git checkout mirror
  • 现在运行git push github
  • 你的Git将——基于它现在看到的,因此假设这是它再次看到的——而不是试图推送任何东西

出现这种情况的原因很可能是您已将push.default配置或默认为simple。当push.default设置为simple时,没有refspec参数的git push会尝试推送当前分支,但仅当其他Git有一个同名分支时。因此,如果github(即https://github.com/...)的Git仍然没有名为mirror的分支,那么你的Git会对自己说:啊。没有名为mirror的分支。最好不要推任何东西

(如果明天,GitHub上的另一个Git确实有一个名为mirror的分支,你的Git会对自己说:啊哈!有一个名称为mirror的分支!好吧,我会要求其他Git更新其mirror)

为什么不"镜像推送到主"?

因为它没有。即使您重新配置了push.default,也没有默认设置意味着"如果我不能给git push一个refspec,请制作一个不匹配的。">

关于refspecs的简短片段

所有这些都基于参考规范的概念。在Git中,refspec本质上是一对引用

引用是"分支或标记名称"的花哨单词。(它可能不仅仅是这两个,但这是主要的两个。)像master这样的分支名称由于其完整拼写refs/heads/master而很短。这个引用名称refs/heads/master是Git用来表示"不仅是master,还有分支master"的方式。像CCD_ 84这样的短标签名称是参考名称CCD_。如果你去掉refs/heads/refs/tags/部分,Git通常会通过查看你现在拥有的分支和标签来判断你指的是哪一个。

无论如何,一个refspec通常只是其中两个,中间有一个冒号:

refs/heads/master:refs/heads/master

例如。您需要其中两个,因为您正在使用两个Git:一个在您的系统上,您要求它做一些事情,另一个在一些远程上,如gitlabgithub。你让你的Git通过互联网电话调用另一个Git。然后你的Git和他们的Git相互交谈,然后你的Git会获取推送东西。

获取和推送步骤需要为每个Git提供一个引用,这意味着您需要两个引用:一个refspec。

refspec的两半是目标。如果您正在运行git fetch,那么源代码是其他Git,目标代码是您自己的Git。如果您正在运行git push就是源;另一个Git成为目的地。但在任何一种情况下,源都会向目标提交一些提交,然后源的名称(refspec的左半部分)被用来更改目标的name中的某些内容,即refspec右半部分。

对于git fetch,在每一侧都有不同的名称是完全正常的。我们获取他们的refs/heads/master写入我们自己的refs/remotes/origin/master。我们从他们的refs/heads/master中提取并写入我们自己的refs/remotes/mirror/master。这让我们可以从一堆不同的地方取东西,但又能让它们保持原样。

不过,对于git push,在每一侧使用相同的名称要正常得多。我们从他们的master中提取,进入我们的refs/remotes/.../master。然后,我们工作一段时间,确保我们的master中的任何内容都是在其master之上的更新,例如通过合并或重新定基。然后,我们再次打电话给他们,交付我们的新提交,并要求他们将他们的master——不是他们甚至没有的nando/master,而是他们的master——设置为建立在他们以前提交基础上的最新提交。

我们确保它建立在他们的基础上,先获取,然后工作,然后推动。如果我们在与索菲亚的"比赛"中失利——我们都获得了大约相同的时间,但她工作得更快,然后她在我们之前推动——我们会得到"远程拒绝"不快进"的错误;我们必须再次获取,从GitHub或任何地方获取Sofia的作品,并使我们的作品建立在她的作品之上,然后再次尝试推送。

"本地过期"是什么意思?

当您的git remote show通过互联网电话呼叫远程设备,特别是github,即https://github.com/nandoquintana/repo.git时,其他Git说:

I have these references:
refs/heads/master  <some big ugly hash ID>

(试着运行git ls-remote github看看他们有什么,你会得到完整的列表)。

您自己的Git有一个名为master的分支,但您的Git为refs/heads/master(您的master分支)提供的大而丑陋的哈希ID是不同的。

由于两者不同,Git假设你要么"领先"——你有一些没有的提交——要么"落后"(他们有一些你没有的提交),或者两者兼而有之。如果你落后了,你的Git无法告诉你落后了多远,但通过查看你的所有提交,它可以告诉你"领先"了多远。如果您的提交129bca4f...的父级是e033fc12...,并且它们处于提交e033fc12...,那么您只领先一个提交。

如果你的Git可以在master分支的历史记录中找到他们的Git提交哈希ID,那么你就"领先"了,你可能现在就可以git push向他们发送你的新提交,要求他们将master设置为129bca4f...,他们可能会接受提交并更新master

但是,如果他们提交了930ab988...,而你根本没有提交,那么你的Git只知道他们有一些提交,而你没有。你一定是"落后"了。您可以从他们那里git fetch,获得他们所有您没有的提交,并使用refs/remotes/github/master记住它们。然后,您可以不惜一切代价将这些提交添加到您自己的master中,这样您就可以与它们持平——既不领先也不落后——并做任何额外的工作,这样您现在就可以领先于它们。

这取决于你是否是个好主意,如果是,是否这样做。git remote show所做的就是通过互联网电话用git ls-remote给他们打电话,并将他们的参考文献与你的参考文献进行比较,根据这些结果猜测git fetchgit push会做什么。(如果使用git pull,则意味着运行git fetch,然后运行git mergegit remote show命令也会尝试猜测这会做什么。)

最新更新