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

标签 git 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 执行简单任务并使其变得困难的另一个实例。

这是另一台机器上的 View 。该分支显然存在,因此它被创建和推送:
$ 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

最佳答案

TL;DR:git branch --set-upstream-to origin/solaris
您提出的问题的答案 - 我将稍微改写为“我是否必须设置上游” - 是:不,您根本不必设置上游。

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

这里完整的推送故事又长又无聊,历史可以追溯到 Git 1.5 版本之前。为了大大缩短它, git push 的实现很差。1 从 Git 2.0 版开始,Git 现在有一个拼写为 push.default 的配置旋钮,现在默认为 simple 。对于 2.0 之前和之后的多个 Git 版本,每次运行 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 有上游 U,则 git rev-parse U 应该可以工作。如果它不起作用——如果它提示 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 会通过查询当前分支的上游来确定要从哪个远程获取。如果上游是远程跟踪分支,则 Git 从该远程获取。 (如果上游没有设置或者是本地分支,Git 会尝试获取 origin 。)

上游也会影响 git mergegit rebase
如果您在没有其他参数的情况下运行 git mergegit rebase,Git 将使用当前分支的上游。所以它缩短了这两个命令的使用。

上游影响git pull
无论如何,您永远都不应该使用 git pull,但是如果您这样做了,git pull 会使用上游设置来确定要从哪个远程获取数据,然后确定要与哪个分支 merge 或 rebase 。也就是说, git pullgit fetch 做同样的事情——因为它实际上运行的是 git fetch——然后和 git mergegit rebase 做同样的事情,因为它实际上运行的是 7x1045 或 67

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

上游影响git merge
这实际上可能是最重要的。一旦你有一个上游集,git rebase 可以报告你当前分支与其上游之间的差异,就提交而言。

如果像正常情况一样,您在分支 git status 上,其上游设置为 git status ,并且您运行 B ,您将立即看到您是否有可以推送的提交,和/或可以 merge 或 rebase 的提交。

这是因为 origin/B 运行:

  • git status :您在 git status 上有多少不在 git rev-list --count @{u}..HEAD 上的提交?
  • B :您在 origin/B 上有多少不在 git rev-list --count HEAD..@{u} 上的提交?

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

    为什么 origin/B 已经有一个上游集?

    当您第一次从某个远程克隆时,使用:
    $ git clone git://some.host/path/to/repo.git
    

    或类似的,Git 所做的最后一步基本上是 B 。这会检查您的本地分支 master - 只有您没有本地分支 git checkout master

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

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

    对于您还没有的每个分支 master 都会发生这种情况。 Git 创建分支并使其“跟踪”(作为上游)相应的远程跟踪分支。

    但这不适用于新分支,即还没有远程跟踪分支的分支。

    如果您创建一个新分支:
    $ git checkout -b solaris
    

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

    当您第一次推送新分支时:
    $ git push origin solaris
    

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

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

    大概。请参阅“实现不佳”和脚注 1。现在很难改变:有数百万个脚本使用 Git,其中一些很可能取决于其当前的行为。改变行为需要一个新的主要版本,nag-ware 强制你设置一些配置字段,等等。简而言之,Git 是其自身成功的受害者:今天,无论它有什么错误,只有在更改几乎不可见、明显好得多或随着时间的推移缓慢完成时,才能修复。

    事实是,今天不会,除非您在 origin/solaris 期间使用 solaris--set-upstream 。这就是消息告诉你的。

    你不必那样做。好吧,正如我们上面提到的,您根本不必这样做,但假设您想要一个上游。您已经通过较早的推送在 -u 上创建了分支 git push,正如您的 solaris 输出所示,您的本地存储库中已经有了 origin

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

    要立即设置,而不是在第一次推送期间,请使用 origin/solarissolaris 子命令采用任何现有分支的名称,例如 git branch --set-upstream-to ,并将当前分支的上游设置为另一个分支。

    就是这样 - 这就是它所做的 - 但它具有上述所有含义。这意味着您可以只运行 --set-upstream-to ,然后环顾四周,然后根据需要运行 origin/solarisgit fetch ,然后进行新的提交并运行 git merge ,而无需额外的大惊小怪。

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

    2“从不”有点强,但我发现当我把这些步骤分开时,Git 新手会更好地理解事情,尤其是当我可以向他们展示 git rebase 实际做了什么,然后他们可以看到 git pushgit fetch 下一步会做什么.

    3如果您将第一个 git merge 作为 git rebase 运行——即,如果添加 git push 标志——如果(且仅当)推送成功,Git 会将 git push -u origin solaris 设置为当前分支的上游。所以你应该在第一次推送时提供 -u。实际上,您可以在以后的任何推送中提供它,并且它会在那时设置或更改上游。但我认为 origin/solaris 更容易,如果你忘记了。

    4 无论如何,通过 Austin Powers/Dr Evil 简单地说“one MILLLL-YUN”的方法来衡量。

    关于git - 为什么我必须 "git push --set-upstream origin <branch>"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37770467/

    相关文章:

    tfs - 在一个项目中创建一个分支,其父级在 TFS 中的另一个项目下

    git:具有提交限制的累积差异

    git - 向我的免费 G​​itHub 帐户添加协作者?

    git - 如何使用 rebase 编辑推送的提交消息?

    tfs - 可以从以前的变更集创建分支吗?

    Git 分支仍然与 master 在同一行

    git - 如何在大型仓库上运行 `git clone mirror` 而不会失败?

    git - SSH key 要求在启动代理后输入密码

    linux - 如何列出 Mercurial 中属于不同分支的所有文件?

    mercurial - 如何在推送默认分支时阻止命名分支?