理解“git remote show”命令输出...“为‘git push’配置的本地引用”的含义是什么?

Nan*_*ana 5 git github git-branch

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

  • 本地分支“master”正在跟踪远程分支“origin/master”
  • 本地分支“mirror”正在跟踪远程分支“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
Run Code Online (Sandbox Code Playgroud)

这是“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)
Run Code Online (Sandbox Code Playgroud)

“推”和“拉”命令都可以正常工作:

  • “push”命令将本地分支中提交的编辑发送到“她的”远程分支。
  • “pull”命令将提交从远程分支带到“她的”本地分支。

那么,为什么“为‘git Push’配置的本地引用”是“主站推送到主站”?为什么不“镜子推主”?“本地过时”是什么意思?

@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
Run Code Online (Sandbox Code Playgroud)

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

master pushes to master (local out of date)
Run Code Online (Sandbox Code Playgroud)

这对我来说不是问题,我确信“remotes/github/master”中的代码和本地“master”中的代码是不同的。

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

这是让我安心的消息:

mirror pushes to master (up to date)
Run Code Online (Sandbox Code Playgroud)

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

tor*_*rek 3

[给我自己和 OP 的一些提醒:远程origin= GitLab,远程github= GitHub。从根本上来说,使用的主要问题git remote show是它做出假设。这些假设是关于您将来如何运行其他 Git 命令\xe2\x80\x94git fetchgit push\xe2\x80\x94,以及将来如何布局每个 Git 命令涉及的第二个 Git 存储库。显然,按照一句古老的丹麦谚语很难做出预测,尤其是对未来的预测。]

\n\n

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

\n\n
\n

这是让我安心的消息:

\n\n
mirror pushes to master (up to date)\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n
\n\n

有一件事情值得一试:一个push.default设置upstream告诉 Git 默认情况下git push应该执行此操作。如果它有效并且达到了您想要的效果,那么您就一切就绪了。但请注意,无论 Git 在这里说什么,它都是谎言。

\n\n

根本问题是mirror 推动master. 在您输入git push命令之前,它根本不会推送任何内容;一旦您输入该命令,您就可以控制该命令执行位置,这可以完全覆盖任何声明git pushgit remote show

\n\n

git push当时的选择是:

\n\n
    \n
  • 不提供额外的参数。

    \n\n

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

    \n\n

    此时,您的 Git 将继续处理此处列出的第二种情况。

  • \n
  • 提供一个附加参数。该参数指定要连接的其他 Git。它通常是一个远程origingithub),但此时您可以提供一个 URL,例如。

  • \n
  • 提供两个或多个附加参数。其中第一个名称为远程(或者是 URL)。其余的是refspecs,定义如下。

  • \n
\n\n

此时,您的 Git 连接到该远程服务器,并且实际上运行git ls-remote以查看它们有哪些分支。此列表很重要,因为它与您提供的或未能提供的 refspec 一起使用,具体取决于您的push.default设置,并且事实上,当您提供 refspec 时,您只能提供一半refspec。

\n\n

“半个参考规范”的情况尤其有问题。无论你做什么或设置什么,如果你git push github mirror在打开时实际运行mirror,你的 Git 都会要求远程的 Gitgithub进行设置……好吧,这取决于你是否有上游设置,如果没有,您的push.default设置。详细信息位于文档git push,采用 Git 通常的神秘形式。不过,默认值是“half refspec”,该名称的mirror意思是mirror:mirror.

\n\n

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

\n\n

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

\n\n

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

\n\n
    \n
  • 如果您git push在不带参数或git push github不带其他参数的情况下运行,则遥控器将为github.

  • \n
  • 如果您不提供 refspec,则push.default应用该设置:Git 将构建的 refspec 将是mirror:master

  • \n
  • 但是,如果您提供一半的 refspec,即使在多次重新阅读文档之后,我也不确定 Git 将构建什么完整的refspec。我认为这将是mirror:mirror,这不是你想要的。

  • \n
  • 您还可以配置remote.github.push提供默认参考规范的变量。这也可能让你得到你想要的东西,尽管push.default = upstream看起来更简单。

  • \n
\n\n

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

\n\n
\n\n
\n

那么,为什么“为‘git push’配置的本地引用”是“主站推送到主站”?

\n
\n\n

这意味着:

\n\n
    \n
  • 假设您当前的分支是master(即您已经运行git checkout master
  • \n
  • 如果你然后运行git push github不是 git push github more-command-words
  • \n
  • Git\xe2\x80\x94(特别是您自己的Git\xe2\x80\x94)将尝试将当前的推master送到https://github.com/nandoquintana/repo.git\'smaster
  • \n
\n\n

这可能会成功,也可能不会成功,具体取决于 GitHub 上的 Git 服务器如何处理礼貌请求来设置 masterGit 通过此推送请求发送的任何哈希 ID。

\n\n

master(如果您再次运行并没有任何其他参数,情况也是如此git push origin,除了名称origin指的是 GitLab 上的 Git 之外,情况也是如此。)

\n\n

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

\n\n
    \n
  • 所以你就跑了git checkout mirror
  • \n
  • 现在你跑了git push github
  • \n
  • 你的 Git 会\xe2\x80\x94基于它现在看到的内容,因此假设这就是它再次看到的\xe2\x80\x94,不会尝试推送任何东西
  • \n
\n\n

出现这种情况的原因很可能是您已push.default配置或默认为simple. 当push.default设置为 时simplegit push不带refspec参数的分支会尝试推送当前分支,但前提是其他 Git 具有同名分支github因此,如果位于(即 at )的 Githttps://github.com/...仍然没有名为的分支mirror,您的 Git 将会对自己说:嗯。没有命名的分支mirror。最好不要推动任何东西。

\n\n

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

\n\n
\n

为什么不“镜子推主”?

\n
\n\n

因为它没有。即使您重新配置您的push.default,也没有默认设置意味着“如果我无法提供git push参考规范,请创建一个不匹配的参考规范”。

\n\n

关于参考规范的简短片段

\n\n

所有这一切都取决于refspec的概念。在 Git 中, refspec 本质上是一对引用

\n\n

引用是分支或标签名称”的花哨词。(它可以不仅仅是这两个,但它们是主要的两个。)像这样的分支名称master是其完整拼写的简写refs/heads/master。这个引用名称refs/heads/master,是 Git 表达“不仅仅是master分支 master的方式。像这样的短标签名称v1.2是参考名称的简写refs/tags/v1.2。如果您省略了refs/heads/refs/tags/部分,Git 通常会通过查看您现在拥有的分支和标签来确定您指的是哪一个。

\n\n

不管怎样,refspec大多只是其中的两个:,中间有一个冒号:

\n\n
refs/heads/master:refs/heads/master\n
Run Code Online (Sandbox Code Playgroud)\n\n

例如。您需要其中两个,因为您正在使用两个 Git:一个在您的系统上,您要求它做某事,另一个在某个远程上,例如gitlabgithub。您让您的 Git 通过网络电话呼叫另一个 Git。然后你的 Git 和他们的 Git 互相对话,之后你的 Git 将获取推送东西。

\n\n

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

\n\n

refspec 的两部分是目标。如果您正在运行git fetch,则源是另一个Git,目标是您自己的 Git。如果你在奔跑git push就是源头;另一个 Git 成为目的地。但无论哪种情况,源都会向目标提供一些提交,然后源的名称\xe2\x80\x94 refspec\xe2\x80\x94 的左半部分用于更改目标名称中的某些内容\xe2\x80\x94 参考规范的右半部分。

\n\n

对于git fetch,两边有不同的名称是完全正常的。我们从他们的中获取refs/heads/master写入我们自己的refs/remotes/origin/master。我们从他们的中获取refs/heads/master并写入我们自己的refs/remotes/mirror/master。这让我们可以从许多不同的地方获取数据,但又保持它们完整。

\n\n

不过,对于来说,两边使用相同的git push名称更为正常。我们从他们的那里获取,进入我们的。然后我们工作一段时间,确保我们的内容是在他们的基础上进行的更新,例如通过合并或变基。然后我们再次打电话给他们,交付我们的新提交,并要求他们将\xe2\x80\x94不是他们的,他们甚至没有,而是他们的\xe2\x80\x94 到这个基于他们的最新提交以前的提交。masterrefs/remotes/.../master mastermastermasternando/mastermaster

\n\n

我们确保它建立在他们的基础上,先获取,然后工作,然后推送。如果我们输掉了与 Sofia\xe2\x80\x94 的“比赛”,我们都会在同一时间获取数据,但她工作得更快,然后她在我们之前推动\xe2\x80\x94,我们得到“远程拒绝”“不快进”错误; 我们必须再次获取,从 GitHub 或其他地方获取 Sofia 的工作,并使我们的工作构建在她的工作之上,然后再次尝试推送。

\n\n
\n

“本地过时”是什么意思?

\n
\n\n

当你通过网络电话git remote show特别调用远程\xe2\x80\x94 github,即\xe2\x80\x94时,另一个Git说:https://github.com/nandoquintana/repo.git

\n\n
I have these references:\n  refs/heads/master  <some big ugly hash ID>\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

您自己的 Git 有一个名为 的分支,但是您的Git 为您的\xe2\x80\x94your分支\xe2\x80\x94提供的master又大又难看的哈希 ID是不同的。 refs/heads/mastermaster

\n\n

由于两者不同,你的 Git 假设你要么“领先”\xe2\x80\x94,你有一些他们没有的提交\xe2\x80\x94,要么“落后”(他们有一些你没有的提交),或者也许两者兼而有之。如果你落后的话,你的 Git 无法告诉你落后了多远,但它可以通过查看你的所有提交来告诉你“领先”多远。如果您129bca4f...的提交的父级是e033fc12...,并且它们位于 commit e033fc12...,那么您仅领先一次提交。

\n\n

master如果你的 Git 可以在你的分支历史记录中找到他们的 Git 提交哈希 ID ,那么你就“领先”了,你git push现在可能可以向他们发送你的新提交,要求他们将其设置master129bca4f...,他们可能会进行提交并更新它们的master.

\n\n

但是如果他们有提交930ab988...,而你根本没有提交,那么你的 Git 只知道他们有一些你没有的提交。你一定是“落后”的。您可以git fetch从他们那里获取他们拥有而您没有的所有提交,并使用refs/remotes/github/master. 然后,您可以尽一切努力将这些提交添加到您自己的 中master,这样您就可以与它们\xe2\x80\x94 保持一致,既不领先也不落后\xe2\x80\x94,并执行所需的任何其他工作,以便您现在领先于他们。

\n\n

由您决定这是否是个好主意,如果是,是否要这样做。所要做的就是通过网络电话git remote show使用 给他们打电话,并将他们的参考资料与您的参考资料进行比较,根据这些结果猜测要做什么和会做什么。(如果您使用,则仅意味着运行,然后运行。该命令也会尝试猜测这会做什么。)git ls-remotegit fetchgit pushgit pullgit fetchgit mergegit remote show

\n