正确答案有多个部分,这就是为什么如此令人困惑的原因。为了正确理解这一点,让我们从定义一些术语开始:
-
remote 是一个简单的名称,例如 origin 或 upstream。这个名称让 Git 可以存储一个 URL——从技术上讲,一个或多个 URL,但通常只有一个——这样你就可以输入 origin 而不是输入 https://user@host.dom.ain/some/fairly/long/path/to/some/other/repo.git 或类似名称。
Git 有一个内置的、或多或少标准的远程远程命名为origin,它由git clone 创建并自动记住您在运行git clone 时使用的URL。
reference 或 ref 是您用来引用提交的东西,例如分支名称或标签名称,如 master 或 develop。引用有很长的形式:例如,master 实际上是 refs/heads/master。大多数时候你可以只使用短格式而不用担心这个,但是长格式就在那里,这是 Git 内部使用的,用于处理棘手的情况,比如你不小心制作了一个 tag @ 987654332@。 (不要故意这样做,但如果你做错了,长格式总是让你解决问题。)
refspec 本质上是一对由冒号: 字符分隔的引用。例如,master:master 是一个 refspec,refs/heads/develop:refs/heads/develop 也是。但这是 refspec 的一种更复杂的形式:在很多情况下,您可以去掉冒号和第二名,在这种情况下,它看起来就像一个引用。
git push 需要的是,按顺序,一个 remote 后跟一个或多个 refspecs。
这反过来意味着你的问题的答案:
git push origin NEW_BRANCH
... NEW_BRANCH 是指本地分支名称还是远程分支名称(如果有区别)?
实际上有点复杂,因为NEW_BRANCH毕竟不是一个分支名称,它是一个refspec。它只是看起来像一个分支名称!
git push 所做的是调用另一个 Git。另一个 Git 在 URL 上“活着”(或至少回答您的 Git 拨打的 Internet 电话),您的 Git 通过查找遥控器找到该 URL。然后两个 Git 进行对话,您的 Git 在对话中找出他们的 Git 有哪些提交,如果需要,提供他们的 Git new 提交,最后,让 他们的 Git 设置一些 他们的 分支名称,以记住在 您的 Git 存储库中找到的一些提交。 (此时,他们也有这些提交,如果他们以前没有的话,这要归功于中间的对话。)
因此,您在此处给出的 NEW_BRANCH refspec 实际上是 both 名称。当您使用包含冒号的表单时,您可以使用两个不同的名称,甚至可以使用原始哈希 ID:
git push origin master:somebranch
让你的 Git 提供你的新提交,然后设置 他们的 somebranch 指向你的master 指向的相同 提交,或者:
git push origin a123456:refs/heads/somebranch
你的 Git 确保他们有提交 a123456...,然后设置 他们的 somebranch 指向那个特定的提交。1
我不明白 [remote and refspec] 的必要性
嗯,事实上,您通常不需要需要它们。您可能会认为这意味着总是,但由于多种历史原因,事实并非如此。
首先,Git 并不总是有 remotes,所以你可以写出一个 URL 来代替远程名称。2 如果你没有'如果不使用远程或 URL,Git 会找出默认值(通常是 origin)。但是,如果您需要列出 refspec,则必须提供远程或 URL,因为远程或 URL 必须位于参数中的那个位置。
其次,Git 使用默认使用一个过于热情的默认 refspec 一次推送多个分支。今天,它默认使用理智的 refspec 推送一个分支。这应该 - 并且确实! - 使它不需要 refspec,但只有在满足某些条件时才需要。而且,您可以更改这个默认值,使用push.default;如果你这样做了,那会改变你可以省略 refspec(s) 的条件,从而改变远程名称。
使用今天默认的push.default 或simple,Git 会自动找出并使用正确的远程和引用规范如果:
- 当前分支有一个上游集,并且
- 上游命名了远程上同名的分支。
这里的遥控器可以是您的任何遥控器:如果分支xyz 的上游是foo/xyz,则遥控器是foo,foo 上的分支是xyz,因此条件 1 和 2 都是遇到了,git push 会做正确的事。
当您第一次创建新分支时,其上游设置(如果有)取决于您创建该分支的方式。使用git checkout -b <em>name</em> 会为您提供一个新分支name,默认情况下它有no 上游。使用git checkout --track <em>remote/name</em> 会为您提供一个新分支name,其中 remote/name 作为其上游,并且还有其他各种选项可以设置一些上游。
1如果您使用这种形式,您通常必须拼出完整的参考名称。原因是当您使用缩短的名称时,例如 git push origin x234,Git 会扫描您的引用以找出,例如,x234 是 分支 名称还是标签名称。这让你的 Git 告诉他们的 Git:设置你的 refs/heads/x234(分支)或 设置你的 refs/tags/x234(标签)。
2在那些真正旧版本的 Git 中,您总是必须提供一个 URL。正如您可能想象的那样,这有点痛苦。这导致了几次实验,最终产生了 remote 的想法,并且一旦有一个名为 origin 的 标准 遥控器,您就可以完全省略遥控器,只要你也可以省略所有的 refspecs。
这些实验也仍然受到支持。您可以使用work:foo 加上insteadOf 条目将work: 映射到其中的主机名和可选路径。