为什么要调用git branch –unset-upstream来修复?

Why call git branch --unset-upstream to fixup?

谈到Git的高级操作,我更像是个新手。我使用博客框架octopress维护我的博客。虽然Octopress自2011年以来没有任何发展,但它很好地服务于我的目标,所以我至今没有想过要改变任何东西。

仅供参考,我的博客托管在Github页面上。

今天,在处理一个新的帖子时,git status显示了以下信息:

1
2
3
On branch source
Your branch is based on 'origin/master', but the upstream is gone.
  (use"git branch --unset-upstream" to fixup)

对所有后续命令重复相同的消息,如git add .git commit -m 'message'git push origin source

  • 这条信息是什么意思?
  • 什么东西坏了吗?
  • 如果是,什么?
  • 我需要修一下吗?

如果可能的话,请指给我一篇PDF/Web文章,在那里我可以读到这篇文章,并为将来理解它。

更多详细信息:

1
2
3
4
5
6
7
8
9
10
11
bash-3.2$ git branch -a
* source
  remotes/octopress/2.1
  remotes/octopress/HEAD -> octopress/master
  remotes/octopress/gh-pages
  remotes/octopress/linklog
  remotes/octopress/master
  remotes/octopress/refactor_with_tests
  remotes/octopress/rubygemcli
  remotes/octopress/site
  remotes/origin/source

如果需要更多信息,请告诉我。谢谢。


tl;dr版本:远程跟踪分支origin/master以前存在,但现在不存在,所以本地分支source正在跟踪不存在的东西,这最多是可疑的,这意味着另一个git功能无法为您做任何事情,git警告您。你一直相处得很好,没有"上游跟踪"功能按预期工作,所以是否改变任何东西取决于你。好的。

对于另一个上游设置,请参见为什么必须"git push--set upstream origin"?好的。

这个警告在Git中是一个新东西,在Git 1.8.5中首次出现。发行说明仅包含一个简短的项目符号:好的。

  • "git branch -v -v" (and"git status") did not distinguish among a
    branch that is not based on any other branch, a branch that is in
    sync with its upstream branch, and a branch that is configured with an
    upstream branch that no longer exists.

要描述它的含义,首先需要了解"远程"、"远程跟踪分支",以及Git如何处理"跟踪上游"。(远程跟踪分支是一个非常有缺陷的术语——我已经开始使用远程跟踪名称,我认为这是一个轻微的改进。不过,在下面,我将使用"远程跟踪分支"来与Git文档保持一致。)好的。

每个"远程"都只是一个名称,在本例中类似于originoctopress。它们的目的是记录诸如git fetchgit pull更新位置的完整URL之类的内容。当您使用git fetch remote,1时,git将转到该远程(使用保存的URL)并带来适当的更新集。它还使用"远程跟踪分支"记录更新。好的。

"远程跟踪分支"(或远程跟踪名称)只不过是某个"远程"上最后看到的分支名称的记录。每个远程本身就是一个Git存储库,所以它有分支。远程"源站"上的分支记录在您的本地存储库中的remotes/origin/下。你展示的文字上说,在origin上有一个分支机构,名为source,在octopress上有一个分支机构,名为2.1linklog等等。好的。

(当然,"普通"或"本地"分支只是您在自己的存储库中创建的分支名称。)好的。

最后,您可以设置一个(本地)分支来"跟踪"一个"远程跟踪分支"。当本地分支L设置为跟踪远程跟踪分支R时,git会将R称为"上游",并告诉您是否"超前"和/或"落后"(就提交而言)。本地分支和远程跟踪分支使用相同的名称(除了远程前缀部分)是很正常的(甚至是推荐的),比如sourceorigin/source,但实际上并不必要。好的。

在这种情况下,这是不可能的。您有一个本地分支source跟踪一个远程跟踪分支origin/master。好的。

你不需要知道git如何建立本地分支来跟踪远程分支的确切机制,但是它们在下面是相关的,所以我将展示这是如何工作的。我们从你当地的分行名称开始,source。有两个使用此名称的配置条目,拼写为branch.source.remotebranch.source.merge。从您显示的输出中,很明显这两个参数都已设置,因此如果运行给定的命令,您将看到以下内容:好的。

1
2
3
4
$ git config --get branch.source.remote
origin
$ git config --get branch.source.merge
refs/heads/master

把这些放在一起,2这告诉Git你的分支source跟踪你的"远程跟踪分支"origin/master。好的。

但是现在看看git branch -a的输出,它显示了存储库中的所有本地和远程跟踪分支名称。远程跟踪名称列在remotes/下。也没有remotes/origin/master。可能曾经有过,但现在不见了。好的。

Git告诉您可以使用--unset-upstream删除跟踪信息。这将清除branch.source.originbranch.source.merge,并停止警告。好的。

不过,您可能希望从跟踪origin/master切换到跟踪其他内容:可能是origin/source,但可能是octopress/的名称之一。好的。

您可以使用git branch --set-upstream-to,3执行此操作,例如:好的。

1
$ git branch --set-upstream-to=origin/source

(假设你仍然在"来源"分支上,而origin/source是你想要的上游,我无法告诉你到底想要哪一个,如果有的话)。好的。

(另请参见如何使现有Git分支跟踪远程分支?)好的。

我想你在这里的方式是,当你第一次做一个git clone的时候,你克隆的东西有一个master分支。您还有一个分支master,它被设置为跟踪origin/master(这是一个普通的、标准的git设置)。这意味着你把branch.master.remotebranch.master.merge设置为originrefs/heads/master。但后来你的origin遥控器把它的名字从master改为source。我相信你也把你的本地名字从master改为source。这将您的设置名称从branch.master.remote更改为branch.source.remote,从branch.master.merge更改为branch.source.merge。但它留下了旧的价值观,所以branch.source.merge现在是错误的。好的。

就在这时,"上游"链接断开了,但在1.8.5之前的Git版本中,Git从未注意到断开的设置。既然你有了1.8.5,它就指出了这一点。好的。

这涵盖了大部分问题,但不是"我需要解决它吗"的问题。很可能你多年来一直在努力解决这个问题,通过做git pull remote branch(例如,git pull origin source)。如果你继续这样做,它将继续解决问题,所以,不,你不需要解决它。如果您愿意,您可以使用--unset-upstream删除上游并停止投诉,并且不将本地分支source标记为有任何上游。好的。

上游的目的是使各种操作更加方便。例如,如果上游设置正确,git fetch后面跟git merge一般会"做正确的事情",而git fetch后面的git status会告诉你,对于该分支,你的回购是否匹配上游的回购。好的。

如果您需要方便,请重新设置上游。好的。

1git pull使用git fetch,从git 1.8.4开始,这个(最后!)同时更新"远程跟踪分支"信息。在旧版本的Git中,更新没有记录在使用git pull的远程跟踪分支中,只使用git fetch。因为您的Git必须至少是1.8.5版,所以这不是您的问题。好的。

这个加上一条配置线,我故意忽略了在remote.origin.fetch下发现的配置线。Git必须映射"合并"名称,以确定远程分支的完整本地名称是refs/remotes/origin/master。不过,映射几乎总是这样工作的,所以可以预测,master会转到origin/master。好的。

3或,使用git config。如果你只想把上游设置为origin/source,唯一需要改变的是branch.source.mergegit config branch.source.merge refs/heads/source。会的。但江户十一〔16〕说你想做什么,而不是让你自己去做,所以这是一种"更好的方式"。好的。好啊。


托雷克的回答可能是完美的,但我只是想让记录员提到另一个不同于原始问题中描述的情况,但同样的错误可能会出现(因为它可能帮助其他有类似问题的人):

我在一台服务器上使用git init --bare创建了一个空的(新的)repo。然后我让git clone把它放到我电脑上的一个本地工作区。

在本地回购上提交单个版本后,我在调用git status后得到了这个错误。

在Torek的回答之后,我了解到发生的事情是本地工作目录repo上的第一次提交创建了"master"分支。但是在远程报告(在服务器上)上,没有任何内容,所以甚至没有"master"(远程/源站/主服务器)分支。

在本地repo运行git push origin master之后,远程repo最终拥有了一个主分支。这使错误不再出现。

因此,总结一下,对于一个新的零提交的远程回购来说,可能会出现这样的错误,因为它没有分支,包括"master"。


对我来说,以东十一〔十四〕已经腐败了。

我做了以下工作,为我解决了这个问题。

1
2
3
rm .git/refs/remotes/origin/master
git fetch
git branch --set-upstream-to=origin/master


这可能会解决你的问题。

完成更改后,您可以提交它,然后

1
2
3
git remote add origin https://(address of your repo) it can be https or ssh
then
git push -u origin master

希望它对你有用。

谢谢


我有过两次这个问题,它总是由我本地分支的Git缓存文件的损坏引起的。我通过将丢失的提交哈希写入该文件来修复它。我从服务器获得了正确的提交哈希,并在本地运行了以下命令:

1
2
3
cat .git/refs/remotes/origin/feature/mybranch \
echo 1edf9668426de67ab764af138a98342787dc87fe \
>> .git/refs/remotes/origin/feature/mybranch


实际上,托雷克已经告诉过你如何更好地使用这些工具。但是,在这种情况下,如果您遵循http://octopress.org/docs/deployment/github/上的指导原则,我认为指出一些特别的地方是很重要的。也就是说,您的设置中将有多个Github存储库。首先是目录$WEBSITE中包含了您网站的所有源代码,然后是仅包含静态生成文件的目录$WEBSITE/_deploy。安装程序的有趣之处在于,在$WEBSITE目录中有一个.gitignore文件,因此这个安装程序实际上可以工作。

足够的介绍。在这种情况下,错误也可能来自_deploy中的存储库。

1
2
3
4
5
6
cd _deploy

git branch -a
* master
remotes/origin/master
remotes/origin/source

.git/config中,您通常需要找到如下内容:

1
2
3
4
5
6
7
8
9
10
11
[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
[remote"origin"]
    url = [email protected]:yourname/yourname.github.io.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch"master"]
    remote = origin
    merge = refs/heads/master

但在您的情况下,分支主机没有远程。

1
2
3
4
5
6
7
8
[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
[remote"origin"]
    url = [email protected]:yourname/yourname.github.io.git
    fetch = +refs/heads/*:refs/remotes/origin/*

你可以通过以下方法来解决:

1
2
cd _deploy
git branch --set-upstream-to=origin/master

所以,一切都是托雷克告诉你的,但重要的是要指出,这很可能涉及到_deploy目录,而不是你网站的根目录。

附言:用一个像zsh这样的shell加上一个git插件,将来可能不会被这个东西咬。它将立即显示_deploy涉及不同的存储库。