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

2nbm6dog  于 2023-05-21  发布在  Git
关注(0)|答案(8)|浏览(144)

我创建了一个本地分支来测试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 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
zyfwsgd6

zyfwsgd61#

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

您提出的问题的答案-我将其重新措辞为“我必须设置上游吗”-是:不,你根本不需要设置upstream。
但是,如果当前分支没有upstream,Git会改变它在git push和其他命令上的行为。
这里完整的推送故事很长很无聊,可以追溯到Git版本1.5之前。1从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 * 被 * 配置为避免过去的错误之一。

什么是上游?

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

每个分支具有具有一(1)个上游集合的选项。也就是说,每个分支要么有上游,要么没有上游。任何分支都不能有一个以上的上游。
上游 * 应该 *,但不一定是有效的分支(无论是像origin/*B*这样的远程跟踪还是像master这样的本地跟踪)。也就是说,如果当前分支 B 有上游 U,则git rev-parse *U* * 应该 * 工作。如果它不工作-如果它抱怨 U 不存在-那么大多数Git的行为就好像上游根本没有设置一样。一些命令,如git branch -vv,将显示上游设置,但将其标记为“gone”。

上游有什么用?

如果您的push.default被设置为simpleupstream,则上游设置将使git push(不带任何附加参数)正常工作。
这就是它对git push所做的一切。但这是相当重要的,因为git push是一个简单的打字错误会导致严重头痛的地方之一。
如果您的push.default设置为nothingmatchingcurrent,则设置upstream对git push没有任何作用。
(All假设你的Git版本至少是2.0。

上行影响git fetch

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

上行也影响git mergegit rebase

如果你不带任何附加参数运行git mergegit rebase,Git会使用当前分支的upstream。因此它缩短了这两个命令的使用。

上行影响git pull

无论如何都不应该2使用git pull,但是如果使用了,git pull会使用upstream设置来确定从哪个remote获取,然后使用哪个分支进行合并或变基。也就是说,git pullgit fetch做同样的事情-因为它实际上运行 * git fetch-然后与git mergegit rebase做同样的事情,因为它实际上运行 * git mergegit rebase
(You我通常应该手动完成这两个步骤,至少直到你足够了解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 * 上?

设置一个upstream会给你所有这些东西。

为什么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创建分支 * 并 * 使其“跟踪”(作为上游)相应的远程跟踪分支。

但这不适用于 new 分支,即尚未 * 远程跟踪分支的分支。

如果创建一个 new 分支:

$ git checkout -b solaris

到目前为止,还没有origin/solaris。您的本地solaris * 无法 * 跟踪远程跟踪分支origin/solaris,因为它不存在。
第一次推送新分支时:

$ git push origin solaris

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

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

可能吧,见“执行不力”和脚注1。现在很难改变:有数以百万计的脚本使用Git,其中一些可能依赖于它的当前行为。更改行为需要一个新的主要版本,nag-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,而无需一堆额外的麻烦。
1公平地说,当时并不清楚最初的实现是否容易出错。只有当每个新用户每次都犯同样的错误时,这一点才变得清晰起来。现在是“不那么穷了”,这并不是说“很棒”。
2“Never”这个词有点过了,但是我发现当我把步骤分开时,Git新手会更好地理解事情,特别是当我可以向他们展示git fetch实际做了什么,然后他们可以看到git mergegit rebase下一步会做什么。
3如果你将 firstgit push作为git push -u origin solaris运行--也就是说,如果你添加了-u标志--当(且仅当)推送成功时,Git会将origin/solaris设置为当前分支的上游。所以你应该在 * 第一次 * 推送时提供-u。事实上,你可以在以后的任何推送中提供它,它会在那个时候设置 * 或更改 * 上游。但我认为git branch --set-upstream-to更容易,如果你忘记了。
无论如何,用奥斯汀·鲍尔斯/邪恶博士简单地说“一个百万云”的方法来衡量。

cnjp1d6j

cnjp1d6j2#

之间的区别

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

zsbz8rwp

zsbz8rwp3#

你可以配置git来自动执行这个操作:
git config --global push.default current
这是你在99%的情况下想要的,无论如何,在我的经验。

j91ykkif

j91ykkif4#

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

ws51t4hk

ws51t4hk5#

在Git 2.37.0版本中,不需要使用--set-upstream origin。你可以在启用push.autoSetupRemote后直接使用git push,方法如下:

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

来源:James Ide's tweet
希望这有帮助!

jdzmm42g

jdzmm42g6#

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

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

所以如果你的本地分支名字是咖啡

git push -u origin coffee
oxiaedzo

oxiaedzo7#

我的理解是,-u--set-upstream允许您为您所在的分支指定上游(远程)存储库,因此下次运行git push时,您甚至不必指定远程存储库。
推流设置上游(远程)仓库为原点:

$ git push -u origin

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

$ git push
4si2a6ki

4si2a6ki8#

tl;dr如果你不想考虑这一点,也不想修改你的配置:
git push --set-upstream origin $(git branch --show-current)

相关问题