为什么我要“git push -set-upstream origin <branch>& gt;”?

我为测试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
642983 次浏览

一个基本完整的命令就像git push <remote> <local_ref>:<remote_ref>。如果你只运行git push, git不知道该做什么,除非你做了一些配置来帮助git做决定。在git回购中,我们可以设置多个遥控器。我们还可以将本地引用推入到任何远程引用。使用full命令是最直接的推入方式。如果你想输入更少的单词,你必须先配置,比如——set-upstream。

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


你问的问题的答案——我将重新措辞为“我必须设置上游吗”——是:不,你根本不需要来设置上游。

但是,如果当前分支没有upstream, Git会改变它在git push和其他命令上的行为。

这里完整的推送故事又长又无聊,可以追溯到Git 1.5版本之前。简单来说,git push的实现很糟糕。从Git 2.0版本开始,Git现在有一个拼写为push.default的配置旋钮,现在默认为simple。在Git 2.0之前和之后的几个版本中,每次你运行git push时,Git都会发出大量噪音,试图说服你设置push.default,只是为了让git push关闭。

你没有提到你正在运行哪个版本的Git,也没有提到你是否配置了push.default,所以我们必须猜测。我的猜测是你正在使用Git版本2-point-something,并且你已经将push.default设置为simple来让它关闭。确切地说,你拥有的是哪个版本的Git,如果你有push.default设置为的话,这很重要,因为这段漫长而无聊的历史,但最终,你从Git那里得到另一个抱怨的事实表明你的Git 配置避免了过去的一个错误。

什么是上游?

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

每个分支都可以选择拥有一个(1)上游集。也就是说,每个分支要么有上游,要么没有上游。任何分支都不能有一个以上的上游。

上游应该(但不一定是)是一个有效的分支(无论是像origin/B这样的远程跟踪,还是像master这样的本地跟踪)。也就是说,如果当前分支B具有上游Ugit rev-parse U 应该工作。如果它不起作用——如果它抱怨U不存在——那么大部分Git就会认为上游根本没有设置。一些命令,如git branch -vv,将显示上游设置,但将其标记为“gone”。

上游有什么好处?

如果你的push.default被设置为simpleupstream,上游设置将使没有附加参数的git push生效。

这就是它对git push所做的一切。但这是相当重要的,因为git push是一个简单的拼写错误会导致严重头痛的地方之一。

如果你的push.default被设置为nothingmatching,或current,设置上游对git push没有任何作用。

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

上游影响git fetch

如果你运行git fetch而不带其他参数,Git会通过查询当前分支的上游来计算出要从哪一个远程获取。如果上游是一个远程跟踪分支,Git将从该远程获取。(如果upstream没有设置或者是本地分支,Git会尝试获取origin。)

上游也会影响git mergegit rebase

如果你运行没有附加参数的git mergegit rebase, Git将使用当前分支的上游。所以它缩短了这两个命令的使用。

上游影响git pull

无论如何,你都不应该__abc9使用git pull,但如果你这样做了,git pull将使用upstream设置来确定从哪个远端获取,然后使用哪个分支合并或重基。也就是说,git pull和__abc3做同样的事情——因为它实际上git pull0 __abc3——然后和git mergegit rebase做同样的事情,因为它实际上git pull0 git mergegit rebase

(您通常应该手动执行这两个步骤,至少在您足够了解Git之前,当其中一个步骤失败时(它们最终会失败),您可以认识到哪里出了问题,并知道如何处理它。)

上游影响git status

这可能是最重要的。一旦你有了上游集合,git status就可以报告你的当前分支和它的上游分支之间的差异。

如果像正常情况一样,你在分支B上,它的上游设置为origin/B,并且你运行git status,你会立即看到你是否有可以推送的提交,和/或可以合并或重基的提交。

这是因为git status运行:

  • git rev-list --count @{u}..HEAD:你在B上有多少次没有在origin/B上提交?
  • git rev-list --count HEAD..@{u}:你在origin/B上有多少次没有在B上提交?

设置上游可以提供所有这些东西。

为什么master已经有了上游集?

当你第一次从远程复制时,使用:

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

或类似,Git执行的最后一步本质上是git checkout master。这将检出你的本地分支master -只是你没有本地分支master

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

Git猜测你的意思一定是:“为我创建一个新的本地master,它指向与远程跟踪origin/master相同的提交,并且,当你这样做的时候,将master的上游设置为origin/master。”

这发生在你尚未拥有的git checkout分支的每一个上。Git创建分支而且,使其“跟踪”(有一个上游)相应的远程跟踪分支。

但这对分支不起作用,即没有远程跟踪分支然而,的分支。

如果你创建一个分支:

$ git checkout -b solaris

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

当你第一次推送新分支时:

$ git push origin solaris

创建 solarisorigin上,因此也在你自己的Git存储库中创建了origin/solaris。但是为时已晚:你已经有了一个本地solaris 没有上游.3.

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

可能。参见“执行不力”和脚注1。很难改变现在:有数百万个使用Git的脚本,其中一些可能取决于它当前的行为。改变行为需要一个新的主要版本,nagg -ware迫使您设置一些配置字段,等等。简而言之,Git是其自身成功的受害者:无论它有什么错误,今天,只有在更改基本上是不可见的、明显更好的或随着时间慢慢进行的情况下才能修复。

事实上,今天不是,你在git push期间使用--set-upstream-u。这就是信息要告诉你的。

你不必这样做的。好吧,正如我们上面提到的,你根本不需要这样做,但让我们说你想要一个上游。通过之前的推送,你已经在origin上创建了分支solaris,正如你的git branch输出所示,你已经在你的本地存储库中 origin/solaris

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

现在要设置它,而不是在第一次推送时,使用git branch --set-upstream-to--set-upstream-to子命令接受任何现有分支的名称,例如origin/solaris,并将当前分支的上游设置为另一个分支。

这就是它——这就是它所做的一切——但它具有上面提到的所有含义。这意味着你可以只运行git fetch,然后四处查看,然后适当地运行git mergegit rebase,然后进行新的提交并运行git push,而不需要一堆额外的麻烦。


公平地说,当时还不清楚最初的实现是否容易出错。只有当每个新用户每次都犯同样的错误时,这一点才变得清晰起来。它现在“不那么穷了”,这并不是说“很棒”。

2“Never”有点强,但我发现当我把步骤分开时,Git新手能更好地理解事情,特别是当我可以向他们展示git fetch实际做了什么,然后他们可以看到git mergegit rebase下一步将做什么。

__abc6如果你运行你的第一个 git push作为__abc1 -即。,如果你添加了-u标志,当(且仅当)推送成功时,git会将origin/solaris设置为当前分支的上游。所以你应该在第一个 push中提供-u。事实上,你可以在以后的任何推送中提供它,并且它会在那时将或改变设置为上游。但我认为git branch --set-upstream-to更简单,如果你忘记了。

__abc0通过《王牌大贱谍》/《邪恶博士》的方法来衡量,简单地说“one mill - yun”。

两者之间的区别

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时都指定要从哪个分支提取。

我的理解是,-u--set-upstream允许你为你所在的分支指定上游(远程)存储库,这样下次运行git push时,你甚至不必指定远程存储库。

推送并设置上游(远程)存储库为原点:

$ git push -u origin

下次推送时,你不必指定远程存储库:

$ git push

-u标志指定你想要将你的本地分支链接到上游分支。如果上游分支不存在,这也将创建一个上游分支。这些答案中没有一个涵盖我是如何做到的(完整的形式),所以它是:

git push -u origin <your-local-branch-name>

因此,如果你的当地的分支名称是咖啡

git push -u origin coffee

如果你忘记添加存储库HTTPS链接,那么把它放在git push <repo HTTPS>

你可以配置git来自动完成:

git config --global push.default current

根据我的经验,这是99%情况下你想要的结果。

如果你不想考虑这个问题,也不想修改你的配置:

git push --set-upstream origin $(git branch --show-current)

在Git 2.37.0版本中,不需要使用——set-upstream origin。 启用push后,可以直接使用git push。

. autoSetupRemote
git config --global --add --bool push.autoSetupRemote true

来源:詹姆斯·井出的推特

希望这能有所帮助!