了解 "git remote show" 命令输出..."Local ref configured for 'git push'" 的含义是什么?

Understanding "git remote show" command output... Which is the meaning of: "Local ref configured for 'git push'"?

我有两个遥控器和两个本地分支机构:

这在我的 .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)

"push" 和 "pull" 命令都可以正常工作:

那么,为什么 "Local ref configured for 'git push'" 是 "master pushes to master"?为什么不 "mirror pushes to master"? "local out of date" 是什么意思?

UPDATED @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" 和 "refs/heads/master" 不相等。这就是 "local out of date" 消息出现的原因:

master pushes to master (local out of date)

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

不过,"remotes/github/master"和本地"mirror"中的代码是一样的。事实上,refs "refs/remotes/github/master" 和 "refs/heads/mirror" 是相等的。

这是一条能让我安心的消息:

mirror pushes to master (up to date)

如何配置 remote/github... 或 push.default... 以获得此输出?

[对我自己和 OP 的一些提醒:远程 origin = GitLab,远程 github = GitHub。从根本上说,使用 git remote show 的主要问题是它做出了 假设 。这些假设是关于你将来如何 运行 其他 Git 命令——git fetchgit push——以及第二个 Git 存储库如何参与每个其中 Git 个命令将在未来列出。显然,old Danish proverb很难做出预测,尤其是关于未来。]

让我在这里解决顶部编辑过的问题:

This is the message that would give me some peace of mind:

mirror pushes to master (up to date)

How could I configure remote/github... or push.default... to get this output?

有一件事值得一试:push.default 设置 upstream 告诉 Git 默认情况下,git push 应该这样做。如果那有效并且做你想做的事,你就准备好了。但请注意,无论 Git 在这里说什么,反正都是谎言。

根本问题是 mirror 不会 推送到 master直到您输入 git push 命令,它根本不会推送任何内容;一旦你输入那个命令,控制哪里with那个git push命令,它可以完全推翻 git remote show 提出的任何声明。

您在 git push 时的选择是:

  • 不提供额外的参数。

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

    此时,您的 Git 继续此处列出的第二个案例。

  • 提供一个附加参数。此参数命名要连接的另一个 Git。它通常是 remoteorigingithub),但此时您可以给出 URL,例如

    ]
  • 提供两个或更多附加参数。其中第一个名称是遥控器(或者是 URL)。其余的是 refspecs,定义如下。

此时,您的 Git 连接到那个遥控器,实际上,运行s git ls-remote 看看他们有什么 b运行 切。此列表很重要,因为它根据您的 push.default 设置与您提供或未能提供的参考规格一起使用,并且当您 do 提供参考规格时,您可以只给出 half 一个 refspec.

"half a refspec" 这种情况特别有问题。无论您做什么或设置什么,如果您在 mirror 上实际上 运行 git push github mirror,您的 Git 将询问远程 Git =14=] 设置...好吧,这取决于你是否有一个上游设置,如果没有,你的 push.default 设置。详细信息在 the git push documentation 中,采用 Git 通常的神秘形式。但是,default 默认值是 "half refspec",名称 mirror 表示 mirror:mirror

如果您提供完整的参考规范,例如 git push github mirror:asdf,参考规范的后半部分确定您的 Git 要求他们的 Git 使用哪个 b运行ch 名称放。如果你给出一半的 refspec,你给出的那一半通常会变成两个名字。使用默认的 push.default = simple,你不能不小心将你的 mirror 推给 任何人 其他人的 master,你必须使用明确的完整 refspec(和那么就看你做对了。

如果您给出 no refspec,您的 Git 将退回到 push.default,并且只有五个设置。默认的 simple 让你的 Git 将你的一组 b运行ches 与他们的一组 b运行ches(来自 git ls-remote)进行比较。如果你的b运行ch,比如mirror没有对应的b运行ch,你的Git就赢了'要求他们 Git 设置 any b运行ches.

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

  • 如果 运行 git push 没有参数,或者 git push github 没有额外的参数,remote 将是 github.

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

  • 但是,如果您提供半个 refspec,我不确定,即使在 re-reading 文档多次之后,full refspec 是什么Git 将建造。我认为会是mirror:mirror,这不是你想要的。

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

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


So, why "Local ref configured for 'git push'" is "master pushes to master"?

这意味着:

  • 假设您当前的 b运行ch 是 master(即,您有 运行 git checkout master
  • 然后如果你 运行 git push github (不是 git push github more-command-words)
  • Git——特别是你自己的 Git——将尝试将你当前的master推向https://github.com/nandoquintana/repo.gitmaster

这可能成功也可能不成功,这取决于 Git Hub 的 Git 服务器对设置 its [=22] 的礼貌请求所做的操作=] 到您的 Git 随此推送请求发送的任何哈希 ID。

(同样适用于 master 和 运行 git push origin,同样没有其他参数,除了名称 origin 指的是 Git 在 Git 实验室。)

另一方面,假设您当前的 b运行ch 名为 mirror:

  • 所以你只是 运行 git checkout mirror
  • 现在你运行git push github
  • 你的 Git 将——基于它现在看到的,因此假设这是它再次看到的——不会 尝试推动 任何东西.

这很可能是因为您将 push.default 配置或默认设置为 simple。当 push.default 设置为 simple 时,没有 refspec 参数的 git push 会尝试推送 current b运行ch,但仅当另一个Git有一个同名的b运行ch。因此,如果 github 处的 Git(即 https://github.com/... 处)仍然没有 具有 一个名为 [=21= 的 b运行ch ],您的 Git 会自言自语:Huh。没有 b运行ch 命名为 mirror。最好不要推任何东西。

(如果明天 GitHub 上的其他 Git 确实 有一个名为 mirror 的 b运行ch,你的 Git 会自言自语:啊哈!有一个名为 mirror 的 b运行ch!好的,我会请其他 Git 更新它mirror.)

why not "mirror pushes to master"?

因为没有。即使您 re-configure 您的 push.default,也没有默认设置意味着 "if I fail to give git push a refspec, make a non-matching one up."

关于 refspecs 的简短片段

所有这些都基于 refspec 的概念。在 Git 中,refspec 本质上是 对引用 .

A reference 是 "branch or tag name" 的花哨词。 (可能不仅仅是这两个,但这是主要的两个。)像 master 这样的 b运行ch 名称的完整拼写是 short-hand,refs/heads/master引用 名称 refs/heads/master 是 Git 对 "not just master, but the branch master" 的表达方式。像 v1.2 这样的短标记名称是 short-hand 引用名称 refs/tags/v1.2。如果您省略了 refs/heads/refs/tags/ 部分,Git 通常会通过查看您现在拥有的 b运行 目录和标签来判断您指的是哪一个。

无论如何,一个 refspec 大部分只是 两个 这些东西中间有一个冒号 ::

refs/heads/master:refs/heads/master

例如。您需要其中两个,因为您正在使用两个 Gits:一个在您的系统上,您要求它做某事,另外一个在某些 remote 上,例如 gitlabgithub。你的 Git 通过 Internet-phone 呼叫了另一个 Git。然后你的 Git 和他们的 Git 互相交谈,之后你的 Git 将 fetchpush 事情。

获取和推送步骤每个 Git 需要一个引用,所以这意味着您需要 两个 引用:一个 refspec.

refspec 的两半是 sourcedestination。如果你运行宁git fetch,源是其他Git,目的地是你自己的Git。如果你是运行宁git push就是来源;另一个 Git 成为目的地。但在任何一种情况下,源都会向目标提交一些提交,然后源的 name——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 中。然后我们工作一段时间,确保 our master 中的任何内容都是在 master 之上的更新,例如通过合并或变基。然后我们再次召集他们,交付我们的新提交,并要求他们设置他们的 master——不是他们甚至没有的 nando/master,而是他们的 master——到这个基于他们之前提交的最新提交。

我们确保它建立在他们的基础上,首先获取,然后工作,然后推送。如果我们与 Sofia 失去了 "race"——我们都获得了相同的时间,但她工作得更快,然后她在我们可以之前推动——我们得到了 "remote rejected" "not fast forward" 错误;我们必须再次获取,从 GitHub 或任何地方获取 Sofia 的工作,并使我们的工作建立在她的工作之上,然后再次尝试推送。

and what does "local out of date" means?

当您的 git remote show 通过 Internet-phone 调出遥控器时——特别是 github,即 https://github.com/nandoquintana/repo.gitother Git 说:

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

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

你自己的 Git 有一个名为 master 的 b运行ch,但是丑陋的大哈希 ID 你的 Git 有你的 refs/heads/master——你的master b运行ch——不一样。

由于两者不同,您的 Git 假设您是 "ahead" — 您有一些他们没有的提交 — 或 "behind" (他们有一些您没有的提交t),或者两者兼而有之。你的Git无法判断你落后多远,如果你完全落后,但它可以判断有多远"ahead" 你是,通过查看你所有的提交。如果您有提交 129bca4f...,其父级为 e033fc12...,并且 它们 处于提交 e033fc12...,那么您仅领先于一次​​提交。

如果您的 Git 可以在您的 master b运行ch 的历史记录中找到他们 Git 的提交哈希 ID,那么您就是 "ahead" 并且您现在可能 git push 将您的新提交发送给他们,要求他们将他们的 master 设置为 129bca4f...,他们可能会接受提交并更新他们的 master

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

由您决定这是否是个好主意,如果是,是否执行。 git remote show 所做的就是调用它们,使用 git ls-remote,而不是 Internet-phone,并将它们的引用与您的引用进行比较,以猜测 git fetchgit push 会做什么, 基于这些结果。 (如果你使用git pull,那就意味着运行git fetch,那么运行git mergegit remote show 命令也会尝试猜测它会做什么。)