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

Why do I have to "git push --set-upstream origin <branch>"?

我创建了一个本地分支来测试 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 上关注了这个问题和答案:Push a new local branch to a remote Git repository and track it too。我猜这是不完整或错误接受答案的另一个实例。或者,它是 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

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

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


您提出的问题的答案(我将其改写为 "do I have to set an upstream")是:不,您 没有 设置上游完全没有。

如果您没有当前 b运行ch 的上游,但是,Git 会更改其在 git push 和其他命令上的行为。

这里的完整推送故事冗长乏味,历史可以追溯到Git 1.5 版本之前。为了大大缩短它,git push 的实现很糟糕。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 配置为避免过去的错误之一。

什么是上游?

An upstream 只是另一个 b运行ch 名称,通常是远程跟踪 b运行ch,与(常规,本地)关联b运行ch.

每个 b运行ch 都可以选择设置一 (1) 个上游。也就是说,每个 b运行ch 要么有上游,要么没有上游。没有b运行ch可以有一个以上的upstream.

上游 应该,但不一定是有效的 b运行ch(是否像 origin/<em>B</em> 或本地 master)。即如果当前b运行chB有上游U,gitrev-解析 <em>U</em> 应该 工作。如果它不起作用——如果它抱怨 U 不存在——那么大多数 Git 就好像根本没有设置上游一样。一些命令,如 git branch -vv,将显示上游设置,但将其标记为 "gone"。

上游有什么好处?

如果您的 push.default 设置为 simpleupstream,上游设置将使 git push 在没有其他参数的情况下正常工作。

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

如果您的 push.default 设置为 nothingmatchingcurrent,设置上游对 git push 没有任何作用。

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

上游影响git fetch

如果你 运行 git fetch 没有额外的参数,Git 通过查询当前的 b[= 计算出从哪个远程获取=347=]ch 的上游。如果上游是一个远程跟踪 b运行ch,Git 从那个远程获取。 (如果未设置上游或者是本地 b运行ch,Git 会尝试获取 origin。)

上游也影响 git mergegit rebase

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

上游影响git pull

你不应该2无论如何使用git pull,但如果你这样做,git pull使用上游设置来确定从哪个远程获取,然后与哪个 b运行ch 合并或变基。也就是说,git pullgit fetch 做同样的事情——因为它实际上 运行s git fetch——然后做同样的事情作为git mergegit rebase,因为它实际上运行sgit mergegit rebase.

(您通常应该手动执行这两个步骤,至少直到您了解 Git 足够清楚,当任一步骤失败时(它们最终会失败),您会认识到哪里出了问题并知道该怎么做它。)

上游影响git status

这实际上可能是最重要的。一旦你有一个上游集,git status 可以报告你当前的 b运行ch 和它的上游之间的差异,就提交而言。

如果正常情况下,您在 b运行ch B 上游设置为 origin/ <em>B</em>,而你运行git status,你会立即看到是否有可以推送的提交,and/or可以推送的提交合并或变基到。

这是因为git status运行s:

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

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

怎么 master 已经有上游集了?

当您第一次从某个远程克隆时,使用:

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

或类似的,最后一步 Git 本质上是 git checkout master。这会检查您的本地 b运行ch master——只是您没有 本地 b运行ch master

另一方面,您确实有一个名为origin/master的远程跟踪b运行ch,因为您刚刚克隆了它。

Git 猜想你的意思一定是:"make me a new local master that points to the same commit as remote-tracking origin/master, and, while you're at it, set the upstream for master to origin/master."

这发生在 每个 b运行ch 你 git checkout 你还没有。 Git 创建 b运行ch and 使其 "track" (作为上游)相应的远程跟踪 b运行ch .

但这不适用于 new b运行ches,即没有远程跟踪的 b运行ches b运行ch .

如果创建 new b运行ch:

$ git checkout -b solaris

目前还没有origin/solaris。您的本地 solaris 无法 跟踪远程跟踪 b运行ch origin/solaris 因为它不存在。

当你第一次推送新的b运行ch:

$ git push origin solaris

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

不应该 Git 直接将其设置为自动上游吗?

可能吧。参见 "implemented poorly" 和脚注 1。现在 很难改变:有数百万4 的脚本使用 Git 和有些很可能取决于其当前的行为。改变行为需要一个新的主要版本,nag-ware 强制你设置一些配置字段,等等。简而言之,Git 是其自身成功的牺牲品:无论它在今天有什么错误,只有在变化基本上不可见、明显好得多或随着时间的推移慢慢完成时才能得到修复。

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

你不必那样做。好吧,正如我们上面提到的,您根本不必这样做,但假设您想要 一个上游。您已经通过之前的推送在 origin 上创建了 b运行ch solaris,正如您的 git branch 输出所示,您已经 拥有 origin/solaris 在您的本地存储库中。

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

要现在设置它,而不是在第一次推送时设置,请使用 git branch --set-upstream-to--set-upstream-to 子命令采用任何现有 b运行ch 的名称,例如 origin/solaris,并将当前 b运行ch 的上游设置为另一个 b运行ch.

仅此而已——仅此而已——但它具有上述所有含义。这意味着您可以 运行 git fetch,然后环顾四周,然后根据需要 运行 git mergegit rebase,然后进行新的提交和 运行 git push,没有一堆额外的麻烦。


1公平地说,当时还不清楚最初的实现容易出错。当每个新用户每次都犯同样的错误时,这一点才变得清晰。现在是"less poor",不是说"great".

2"Never" 有点强,但是我发现 Git 新手在我把步骤分开后更容易理解事情,尤其是当我可以向他们展示 git fetch 实际做了什么,然后他们可以看到 git mergegit rebase 接下来会做什么。

3如果您 运行 您的 第一个 git push 作为 git push -u origin solaris——即,如果您添加 -u 标志 - 如果(且仅当)推送成功,Git 将设置 origin/solaris 作为当前 b运行ch 的上游。因此,您应该在 first 推送中提供 -u。事实上,您可以在以后的任何推送中提供它,它会在那时设置 或更改 上游。但是我觉得 git branch --set-upstream-to 更简单,如果你忘记了。

4通过 Austin Powers / Dr Evil 的方法测量,简单地说 "one MILLLL-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 标志指定您想要 link 您的本地分支到 上游 分支。如果不存在,这也会创建一个上游分支。 None 这些答案涵盖了我是如何做的(完整的形式)所以这里是:

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

因此,如果您的 local 分店名称是 coffee

git push -u origin coffee

如果您忘记添加存储库 HTTPS link 然后将其与 git push <repo HTTPS>

您可以配置 git 自动执行此操作:

git config --global push.default current

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

tl;dr 如果你不想考虑这个但也不想修改你的配置:

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