首页 > 解决方案 > 如果在分支中工作,为什么 git push 需要额外的参数?

问题描述

我做了

git checkout -b NEW_BRANCH

到处都提到,为了将它推送到远程,要么告诉推送命令一些额外的信息

git push origin NEW_BRANCH

,或者必须将本地分支与远程分支相关联

git branch --set-upstream origin NEW_BRANCH

我也不明白两者的必要性。换句话说,我不明白附加命令的效果?这些是什么?或者会发生什么,如果有人说

git 推送

? 在上述任一命令中,NEW_BRANCH 是指本地分支名称还是远程分支名称(如果有差异)?

标签: git

解决方案


正确答案有多个部分,这就是为什么如此令人困惑的原因。为了正确理解这一点,让我们从定义一些术语开始:

  • 遥控器是一个简单的名称,例如originor upstream。这个名称让 Git 可以存储一个 URL——从技术上讲,是一个或多个 URL,但通常只有一个——这样https://user@host.dom.ain/some/fairly/long/path/to/some/other/repo.git你就可以输入origin.

    Git 有一个内置的,或多或少标准的远程命名origin,它由创建git clone并自动记住您在运行时使用的 URL git clone

  • 引用ref是您用来引用提交的东西,例如分支名称或标记名称,例如masteror develop。引用有很长的形式:例如masteris really refs/heads/master。大多数时候你可以只使用短格式而不用担心这个,但是长格式就在那里,这是 Git 内部使用的,用于处理棘手的情况,比如你不小心制作了一个tag master。(不要故意这样做,但如果你做错了,长格式总是让你解决问题。)

  • refspec本质上是一对用冒号分隔的引用:。例如,master:master是一个 refspec,就像refs/heads/develop:refs/heads/develop. 但这是 refspec 的一种更复杂的形式:在很多情况下,您可以删除冒号和第二个名称,在这种情况下,它看起来像一个引用。

需要git push的是,按顺序,一个遥控器后跟一个或多个refspecs

这反过来意味着您的问题的答案:

git push origin NEW_BRANCH

... NEW_BRANCH 是指本地分支名称还是远程分支名称(如果有区别)?

实际上有点复杂,因为这毕竟NEW_BRANCH不是分支名称,而是refspec。它只是看起来像一个分支名称!

什么git push是调用另一个Git。另一个 Git 在 URL 上“活着”(或至少回答您的 Git 拨打的 Internet 电话),您的 Git 通过查找遥控器找到该 URL。然后两个 Git 进行对话,你的 Git 找出他们的 Git 有哪些提交,如果需要,提供他们的 Git提交,最后,要求他们的Git 设置他们的一些分支名称以记住在你的Git 存储库中找到的一些提交. (此时,他们也有这些提交,如果他们以前没有的话,这要归功于中间的对话。)

因此,您在此处给出的NEW_BRANCH refspec实际上是两个名称。当您使用其中包含冒号的表单时,您可以使用两个不同的名称,甚至在您身边使用原始哈希 ID:

git push origin master:somebranch

它让您的 Git 提供您的新提交,然后将它们 somebranch设置为指向您指向的相同提交master,或者:

git push origin a123456:refs/heads/somebranch

这让你的 Git 确保他们已经提交a123456...,然后将它们 somebranch设置为指向那个特定的提交。1

我不明白需要 [remote 和 refspec]

好吧,事实上,您通常不需要它们。您可能认为这意味着always,但由于多种历史原因,事实并非如此。

首先,Git 并不总是有远程,所以你可以写出一个 URL 来代替远程名称。2 如果您不使用远程或 URL,Git 将找出默认值(通常origin)。但是,如果您需要列出 refspec,则必须提供远程或 URL,因为远程或 URL 必须位于参数中的那个位置。

其次,Git过去默认使用过于热情的默认 refspec 一次推送多个分支。今天,它默认使用理智的 refspec 推送一个分支。这应该 - 并且确实! - 使它不需要 refspec,但只有在满足某些条件时才需要。而且,您可以更改此默认值,使用push.default; 如果你这样做了,那会改变你可以省略 refspec(s) 的条件,从而改变远程名称。

使用今天的默认值push.defaultsimpleGit 将自动找出并使用正确的远程和 refspec ,如果:

  1. 当前分支有一个上游集,并且
  2. 上游命名远程上同名的分支。

这里的遥控器可以是你的任何遥控器:如果分支xyz有一个上游foo/xyz,遥控器是foo并且分支fooxyz所以条件1和2都满足并且git push会做正确的事情。

当您第一次创建新分支时,其上游设置(如果有)取决于创建该分支的方式。Using为您提供了一个默认情况下没有上游的新分支。Using为您提供了一个新分支,该分支作为其上游,并且还有各种其他选项可以设置一些上游。git checkout -b namenamegit checkout --track remote/namenameremote/name


1如果您使用此表格,您通常必须拼出完整的参考名称。原因是当你使用缩短的名称时,git push origin x234Git 会扫描你的引用以确定x234分支名称还是标签名称。这让你的 Git 告诉他们的 Git:设置你的 refs/heads/x234(分支)或设置你的 refs/tags/x234(标签)。

2在那些真正旧版本的 Git 中,您总是必须提供一个 URL。正如您可能想象的那样,这有点痛苦。这导致了几次实验,最终产生了remote的想法,并且一旦有一个标准的remote 命名origin,它就允许你完全省略 remote,只要你也可以省略所有的 refspecs。

这些实验也仍然得到支持。您可以使用work:fooplusinsteadOf条目映射work:到其中的主机名和可选路径。


推荐阅读