为什么我必须“ git push --set-upstream origin <branch>”?


146

我创建了一个本地分支来测试Solaris和Sun Studio。然后,我将分支推到上游。提交更改并尝试推送更改后:

$ git commit blake2.cpp -m "Add workaround for missing _mm_set_epi64x"
[solaris 7ad22ff] Add workaround for missing _mm_set_epi64x
 1 file changed, 5 insertions(+)
$ git push
fatal: The current branch solaris has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin solaris

为什么我必须为此做些特别的事情?

是否存在任何合理的用例,有人可以创建该对象<branch>,将其推<branch>送到远程,然后声称<branch>不应该提交<branch>


我在Stack Overflow上遵循了以下问答:将新的本地分支推送到远程Git存储库并进行跟踪。我猜想它的另一个例子是答案不完整或错误。或者,它是Git的另一个实例,它承担着一个简单的任务并使之变得困难。


这是另一台机器上的视图。分支显然存在,因此创建并推送了该分支:

$ git branch -a
  alignas
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/alignas
  remotes/origin/arm-neon
  remotes/origin/det-sig
  remotes/origin/master
  remotes/origin/solaris


2
谢谢@Alexi。不幸的是,引用的dup不能解释默认情况下所代表的荒谬用例。(这些不是花哨的问题。我对UX设计的原因非常感兴趣)。
jww '17

1
请注意,这是可配置的。如果这样做git config --add push.default current,则git push将在必要时在远程仓库中自动创建分支。
Gogowitsch

Answers:


271

TL; DR: git branch --set-upstream-to origin/solaris


这个问题的答案你问哪个,我会改写一个部位为“我要设置一个上游” -is的问题:不,你不具备在所有设置的上游。

但是,如果当前分支没有上游,则Git会在git push和其他命令上更改其行为。

完整的推送故事漫长而无聊,其历史可以追溯到Git 1.5版之前。将其整体缩短很多,git push实施效果不佳。1 从Git 2.0版开始,Git现在有一个拼写的配置旋钮push.default,现在默认为simple。对于2.0之前和之后的多个版本的Git,每次运行时git push,Git都会发出很多噪音,试图说服您进行设置push.defaultgit push使其闭嘴。

您没有提到您正在运行哪个版本的Git,也没有提及您是否已配置push.default,因此我们必须猜测。我的猜测是您使用的是Git版本2点功能,并且已经准备push.defaultsimple将其关闭。正是你有哪些的Git版本,如果有什么事情,你都push.default设置为,的事情,因为那漫长而枯燥的历史,但最终的事实,你要还来自另一个Git的投诉表明你的Git 配置为避免过去的错误之一。

什么是上游?

上游仅仅是另一个分支名称,通常是一个远程跟踪分支,具有(常规,本地)分支相关联。

每个分支都可以选择一(1)个上游集合。也就是说,每个分支都具有上游,也可以不具有上游。没有分支可以有一个以上的上游。

上游应该但不是必须是有效分支(无论是远程跟踪like 还是本地like )。也就是说,如果当前分支B具有上游U,则应该起作用。如果它不起作用-如果它抱怨U不存在-那么大多数Git的行为就好像根本没有设置上游。一些命令(如)将显示上游设置,但将其标记为“ gone”。origin/Bmastergit rev-parse U git branch -vv

上游有什么好处?

如果将your push.default设置为simpleupstream,则上游设置将make git push,不使用其他参数,就可以了。

就这样-这就是它所做的全部git push。但这是相当重要的,因为这git push是简单的错字引起严重头痛的地方之一。

如果您push.default将设置为nothingmatchingcurrent,则设置上游根本不起作用git push

(所有这些都假设您的Git版本至少为2.0。)

上游影响 git fetch

如果git fetch没有其他参数运行,Git会通过咨询当前分支的上游来确定从哪个远程获取。如果上游是远程跟踪分支,则Git从该远程获取。(如果上游未设置或是本地分支,则Git尝试获取origin。)

上游影响git mergegit rebase

如果您运行git mergegit rebase没有其他参数,则Git使用当前分支的上游。因此,它缩短了这两个命令的使用。

上游影响 git pull

无论如何,您永远都不应使用2git pull,但如果这样做,则应git pull使用上游设置来确定要从中获取哪个远程,然后与之合并或变基的分支。也就是说,git pull做同样的事情git fetch-因为它实际上运行 git fetch -然后做同样的事情,git merge或者git rebase,因为它实际上运行 git mergegit rebase

(通常,您通常应该手动执行这两个步骤,至少直到您对Git的了解足够深,以至于当任一步骤失败时,他们最终都会知道出了什么问题并知道该怎么做。)

上游影响 git status

这实际上可能是最重要的。一旦有了上游集,git status就可以报告当前分支与其上游分支之间的差异。

如果正常情况下,如果您在B其上游设置为的分支上并且运行,您将立即看到您是否具有可以推送的提交,和/或可以合并或基于其的提交。origin/Bgit status

这是因为git status运行:

  • git rev-list --count @{u}..HEAD:有多少提交你对B那些不上?origin/B
  • git rev-list --count HEAD..@{u}:有多少提交你对那些不上?origin/BB

设置上游将为您提供所有这些东西。

为什么master已经有了上游产品呢?

首次从某个远程克隆时,请使用:

$ git clone git://some.host/path/to/repo.git

或类似的操作,Git所做的最后一步本质上是git checkout master。此检查出你的本地分支master-只有你没有拥有一个本地分支master

另一方面,您确实有一个名为的远程跟踪分支origin/master,因为您只是克隆了它。

Git的猜测,你一定意味:“让我一个新的地方master,它指向同一个commit,远程跟踪origin/master,并且,当你在它,设定为上游masterorigin/master。”

对于尚未拥有的每个分支都会发生这种情况git checkout。Git创建分支,使它“跟踪”(作为上游)相应的远程跟踪分支。

但是,这并不工作,为新的分支,即没有远程跟踪支支还没有

如果创建分支:

$ git checkout -b solaris

到目前为止,还没有origin/solaris。您的本地solaris 无法跟踪远程跟踪分支,origin/solaris因为它不存在。

首次推送新分支时:

$ git push origin solaris

造成 solarisorigin,因此也创造origin/solaris你自己的Git仓库。但为时已晚:你已经有一个地方solaris没有的上游3

Git现在不应该将其自动设置为上游吗?

大概。请参阅“执行不力”和脚注1。这是很难改变现在:有几百万4使用Git的脚本和一些可能取决于其当前行为。更改行为需要新的主要发行版,使用nag-ware强制您设置某些配置字段等。简而言之,Git是其自身成功的受害者:今天,它所犯的任何错误只有在这种变化大部分是不可见的,明显好得多的或者随着时间的推移而缓慢完成时才能解决。

事实是,除非您在--set-upstream-u期间使用,否则今天不会git push。这就是消息告诉您的内容。

您不必那样做。好吧,正如我们上面提到的,您根本不需要这样做,但是假设您想要上游。你已经创建的分支solarisorigin,通过早期的推动,并作为你的git branch输出显示,你已经 origin/solaris在本地资源库。

您只是没有将它设置为的上游solaris

现在就进行设置,而不是在第一次按下时进行设置git branch --set-upstream-to。该--set-upstream-to子命令采用任何现有分支的名称,例如origin/solaris,并将当前分支的上游设置为该其他分支。

就这样-就是这样-但是它具有上面提到的所有含义。这意味着您可以先运行git fetch,然后环顾四周,然后运行git mergegit rebase根据需要运行,然后进行新的提交并运行git push,而无需进行很多额外的操作。


1公平地说,当时还不清楚最初的实现是否容易出错。只有每个新用户每次都犯相同的错误时,这一点才变得清楚。现在已经“不那么贫穷”了,更不用说“伟大”了。

2 “从不”是一个有点强,但我发现,Git的新手明白了很多东西更好,当我分离出的步骤,特别是当我可以告诉他们什么git fetch实际上做了,然后就可以看到什么git mergegit rebase下一个会做。

3如果您以第一个 git push身份(即git push -u origin solaris添加-u标志)运行,则Git将origin/solaris在(且仅当)推送成功的情况下设置为当前分支的上游。因此,您应该-u首次推送时提供。实际上,您可以在以后的任何推送中提供它,并且它将在该点设置或更改上游。但是git branch --set-upstream-to,如果您忘记了,我认为会更容易。

4用Austin Powers / Evil博士的方法来衡量,无论怎么说,该方法只是简单地说“一个米尔”。


2
如果常见的情况是{create branch / push branch / use branch},那么将新的本地分支推送到远程Git存储库并对其进行跟踪的结果是否也应该有效?并且,如果有人想要{创建分支/推送分支/不使用分支},那么他们不应该做一些特别的事情--set-upstream /dev/null吗?为什么把负担加到普通案件上呢?我真的不理解其中的一些工程和可用性决策。
jww

1
@VonC:对,那是点git push -u,但它确实看起来git push -u应该是默认的,或者至少是默认的,如果没有上游然而,并且应该有一个git push --no-set-upstream当目前还没有一个上游和你想保留这样(出于任何不可理解的原因:-))。
torek

2
“您一直这样问问题,因为我认为您已将Git视为“确实令人讨厌”。请保持这种猜测。我遇到了这个问题,因为我也一直在问自己这些问题。我不是世界上最好的UX设计人员,但是即使我也意识到,在这种特定情况下,默认行为可能会更好。
史蒂文·比克斯

4
@torek-谢谢。否则,您的答案太棒了;经过深思熟虑,结构合理且内容丰富。:-)
史蒂文·比克斯

6
请注意,这是可配置的。如果这样做git config --add push.default current,则git push将在必要时在远程仓库中自动创建分支。
Gogowitsch

31


git push origin <branch>
和之间的区别
git push --set-upstream origin <branch>
是它们都可以很好地推送到远程存储库,但是在您拉出时您会注意到差异。

如果您这样做:
git push origin <branch>
拉动时必须执行以下操作:
git pull origin <branch>

但是如果您这样做:
git push --set-upstream origin <branch>
那么,在拉动时,您只需要做:
git pull

因此,添加--set-upstream允许不必指定每次执行都要从哪个分支拉出git pull


我不知道为什么要/需要使用“ git push”的两个版本之间的差异。无意义!
弗兰克·帕克

17

基本的完整命令就像git push <remote> <local_ref>:<remote_ref>。如果您只运行git push,则git不会确切知道该怎么做,除非您进行了一些有助于git做出决定的配置。在git仓库中,我们可以设置多个遥控器。我们也可以将本地引用推送到任何远程引用。完整命令是进行推送的最直接方法。如果要输入较少的单词,则必须先进行配置,例如--set-upstream。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.