git push:它什么时候创建dst?

git push: when does it create the dst?

我不清楚在什么条件下会创建远程 <dst>。假设 origin 是去一个远程的,在 $git push origin localBranch:newRemoteBranch 如果不存在,将创建 newRemoteBranch。 但是当我使用 <src> 是任意提交的 sha1 哈希的语法时,似乎只有在推送之前存在远程分支时推送才会成功。 有没有办法从任意提交创建远程分支,而不是被迫为 <src> 使用现有的 ref?

TL;DR 版本

你需要语法 git push <em>hash</em>:refs/heads/<em>new-b运行ch</em> 以便他们的 Git 知道您想创建新的 b运行ch(在 "their side",在 他们的 Git,毕竟是普通的b运行ch).

描述

我想我知道你想问什么,但我不确定你应该如何表达这个问题。 (特别是,如果你知道要问 "refspecs",你可以找到答案——但你为什么知道要问这个?)

让我们尝试一个完全不同的问题,但供您思考。假设您创建了一个 tag v0.9alpha,并且 运行:

git push origin v0.9alpha

(与更典型的 git push origin master 相比)。

Git 如何知道您推的是 标签 而不是某个名为 v0.9alpha 的 b运行ch?还要记住,对于 git pushgit fetch,有 两个 Git 涉及,两个 必须知道并同意这类事情。如果你的标签在你推送时变成了 b运行ch,或者你从另一个 Git 获得标签但你的 Git 在本地将它们创建为 b运行ches,那就太糟糕了相反。

当您 运行 git branchgit tag 自己时,很明显您的 Git 如何知道您指的是哪一个:它就在命令中。但是它在 git pushgit fetch 的什么地方?它不在那里......或者是吗?

参考有全名

这些东西的一般形式——这些人类可读的名字,这些 b运行ches,标签,以及你可以用来指代某个提交或其他任何东西的任何其他名字——被称为 reference 和 references "full names"。任何b运行ch的全名都以refs/heads/开头,所以master实际上是refs/heads/master。任何标签的全名都以 refs/tags/ 开头。任何远程跟踪 b运行ch 的全名以 refs/remotes/ 开头; origin 的那些特别以 refs/remotes/origin/.

开头

Git 大多数时候只是 缩短 全名。您输入 master,而不是 refs/heads/master,Git 计算出您的意思是 b运行ch master .您输入 v0.9alpha,然后 Git 计算出您指的是您的标签。您输入 origin/master 并且 Git 也得出一个结果。

推送和获取使用 refspecs

你已经知道你可以写 git push origin localBranch:newRemoteBranch。 Git 调用这个东西—这个 <em>src</em>:<em>dst</em> 对—一个 refspec。这其中的每一半实际上都是一个参考,这是整个谜题的关键。

(refspec 也有一个可选的前导加号。如果它在那里,则表示 --force,但仅针对推送或获取的这一个实例,而不是针对每一对。使用 --forcegit pushgit fetch 表示 "set the force flag on every refspec"。force 标志主要对 b运行ch 名称有意义,尽管它也适用于其他引用。)

如果你只写:

git push origin xyz

您的 Git 将在 您的 存储库中查找一些以 xyz 结尾的参考。 (完整搜索在 the gitrevisions documentation 中描述;这是一个六步过程。)该搜索及其结果告诉 Git 种类 参考 xyz 是——可能是一个 b运行ch,但也可能是一个标签。结果,您自己的 Git 现在知道您指的是 refs/heads/xyz 还是 refs/tags/xyz

你的 Git 然后在与另一个 Git 交谈时使用 相同的 全名,这使得另一个 Git 创建或更新相同的 kind 参考。

但是当你写的时候:

git push origin 91cb035:xyz

相反,您的 Git 不会 通过六步过程来查找散列 91cb035。所以它 还不知道它应该向另一个Git 发送什么样的引用。相反,它采用你的弱指定 xyz,并使用 other Git 必须尝试猜测你的意思是 refs/heads/xyz 还是 refs/tags/xyz,或者完全是其他 xyz

如果您的 Git 猜不出来而他们的 Git 也帮不上忙,因为两者都没有 xyz,那么只有一个正确答案:您的 Git可以让提供全名。你可以 运行:

git push origin 91cb035:refs/heads/xyz

你的 Git 现在知道它应该向另一个 Git 发送全名 refs/heads/xyz。他们的 Git 会将其视为 b运行ch 名称,因为它 就是 .