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

GitGit BranchGithub Pages

Git Problem Overview


I'm more of a novice when it comes to advanced operations in git. I maintain my blog using the blogging framework Octopress. Though Octopress is not under any development since 2011, it serves my purpose well and so I haven't thought of changing anything so far.

FYI, my blog is hosted on Github Pages.

Today, while working on a new post, git status showed the following message:

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

The same message repeated for all the subsequent commands such as git add ., git commit -m 'message' and git push origin source.

  • What does the message mean?
  • Is something broken?
  • If yes, what?
  • Do I need to fix it?

If possible, please point me to a pdf/web article where I can read up on this and understand it for future.

More details:

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

Please let me know if more information is needed. Thanks.

Git Solutions


Solution 1 - Git

TL;DR version: remote-tracking branch origin/master used to exist, but does not now, so local branch source is tracking something that does not exist, which is suspicious at best—it means a different Git feature is unable to do anything for you—and Git is warning you about it. You have been getting along just fine without having the "upstream tracking" feature work as intended, so it's up to you whether to change anything.

For another take on upstream settings, see https://stackoverflow.com/q/37770467/1256452


This warning is a new thing in Git, appearing first in Git 1.8.5. The release notes contain just one short bullet-item about it:

> * "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.

To describe what it means, you first need to know about "remotes", "remote-tracking branches", and how Git handles "tracking an upstream". (Remote-tracking branches is a terribly flawed term—I've started using remote-tracking names instead, which I think is a slight improvement. Below, though, I'll use "remote-tracking branch" for consistency with Git documentation.)

Each "remote" is simply a name, like origin or octopress in this case. Their purpose is to record things like the full URL of the places from which you git fetch or git pull updates. When you use git fetch remote,1 Git goes to that remote (using the saved URL) and brings over the appropriate set of updates. It also records the updates, using "remote-tracking branches".

A "remote-tracking branch" (or remote-tracking name) is simply a recording of a branch name as-last-seen on some "remote". Each remote is itself a Git repository, so it has branches. The branches on remote "origin" are recorded in your local repository under remotes/origin/. The text you showed says that there's a branch named source on origin, and branches named 2.1, linklog, and so on on octopress.

(A "normal" or "local" branch, of course, is just a branch-name that you have created in your own repository.)

Last, you can set up a (local) branch to "track" a "remote-tracking branch". Once local branch L is set to track remote-tracking branch R, Git will call R its "upstream" and tell you whether you're "ahead" and/or "behind" the upstream (in terms of commits). It's normal (even recommend-able) for the local branch and remote-tracking branches to use the same name (except for the remote prefix part), like source and origin/source, but that's not actually necessary.

And in this case, that's not happening. You have a local branch source tracking a remote-tracking branch origin/master.

You're not supposed to need to know the exact mechanics of how Git sets up a local branch to track a remote one, but they are relevant below, so I'll show how this works. We start with your local branch name, source. There are two configuration entries using this name, spelled branch.source.remote and branch.source.merge. From the output you showed, it's clear that these are both set, so that you'd see the following if you ran the given commands:

$ git config --get branch.source.remote
origin
$ git config --get branch.source.merge
refs/heads/master

Putting these together,2 this tells Git that your branch source tracks your "remote-tracking branch", origin/master.

But now look at the output of git branch -a, which shows all the local and remote-tracking branch names in your repository. The remote-tracking names are listed under remotes/ ... and there is no remotes/origin/master. Presumably there was, at one time, but it's gone now.

Git is telling you that you can remove the tracking information with --unset-upstream. This will clear out both branch.source.origin and branch.source.merge, and stop the warning.

It seems fairly likely that what you want, though, is to switch from tracking origin/master, to tracking something else: probably origin/source, but maybe one of the octopress/ names.

You can do this with git branch --set-upstream-to,3 e.g.:

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

(assuming you're still on branch "source", and that origin/source is the upstream you want—there is no way for me to tell which one, if any, you actually want, though).

(See also How do you make an existing Git branch track a remote branch?)

I think the way you got here is that when you first did a git clone, the thing you cloned-from had a branch master. You also had a branch master, which was set to track origin/master (this is a normal, standard setup for git). This meant you had branch.master.remote and branch.master.merge set, to origin and refs/heads/master. But then your origin remote changed its name from master to source. To match, I believe you also changed your local name from master to source. This changed the names of your settings, from branch.master.remote to branch.source.remote and from branch.master.merge to branch.source.merge ... but it left the old values, so branch.source.merge was now wrong.

It was at this point that the "upstream" linkage broke, but in Git versions older than 1.8.5, Git never noticed the broken setting. Now that you have 1.8.5, it's pointing this out.


That covers most of the questions, but not the "do I need to fix it" one. It's likely that you have been working around the broken-ness for years now, by doing git pull remote branch (e.g., git pull origin source). If you keep doing that, it will keep working around the problem—so, no, you don't need to fix it. If you like, you can use --unset-upstream to remove the upstream and stop the complaints, and not have local branch source marked as having any upstream at all.

The point of having an upstream is to make various operations more convenient. For instance, git fetch followed by git merge will generally "do the right thing" if the upstream is set correctly, and git status after git fetch will tell you whether your repo matches the upstream one, for that branch.

If you want the convenience, re-set the upstream.


1git pull uses git fetch, and as of Git 1.8.4, this (finally!) also updates the "remote-tracking branch" information. In older versions of Git, the updates did not get recorded in remote-tracking branches with git pull, only with git fetch. Since your Git must be at least version 1.8.5 this is not an issue for you.

2Well, this plus a configuration line I'm deliberately ignoring that is found under remote.origin.fetch. Git has to map the "merge" name to figure out that the full local name for the remote-branch is refs/remotes/origin/master. The mapping almost always works just like this, though, so it's predictable that master goes to origin/master.

3Or, with git config. If you just want to set the upstream to origin/source the only part that has to change is branch.source.merge, and git config branch.source.merge refs/heads/source would do it. But --set-upstream-to says what you want done, rather than making you go do it yourself manually, so that's a "better way".

Solution 2 - Git

torek's answer is probably perfect, but I just wanted for the record to mention another case which is different than the one described in the original question but the same error may appear (as it may help others with similar problem):

I have created an empty (new) repo using git init --bare on one of my servers. Then I have git cloned it to a local workspace on my PC.

After committing a single version on the local repo I got that error after calling git status.

Following torek's answer, I understand that what happened is that the first commit on local working directory repo created "master" branch. But on the remote repo (on the server) there was never anything, so there was not even a "master" (remotes/origin/master) branch.

After running git push origin master from local repo the remote repo finally had a master branch. This stopped the error from appearing.

So to conclude - one may get such an error for a fresh new remote repo with zero commits since it has no branch, including "master".

Solution 3 - Git

This might solve your problem.

after doing changes you can commit it and then

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

hope it works for you.

thanks

Solution 4 - Git

For me, .git/refs/origin/master had got corrupt.

I did the following, which fixed the problem for me.

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

Solution 5 - Git

Actually torek told you already how to use the tools much better than I would be able to do. However, in this case I think it is important to point out something peculiar if you follow the guidelines at http://octopress.org/docs/deploying/github/. Namely, you will have multiple github repositories in your setup. First of all the one with all the source code for your website in say the directory $WEBSITE, and then the one with only the static generated files residing in $WEBSITE/_deploy. The funny thing of the setup is that there is a .gitignore file in the $WEBSITE directory so that this setup actually works.

Enough introduction. In this case the error might also come from the repository in _deploy.

cd _deploy

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

In .git/config you will normally need to find something like this:

[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

But in your case the branch master does not have a remote.

[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/*

Which you can solve by:

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

So, everything is as torek told you, but it might be important to point out that this very well might concern the _deploy directory rather than the root of your website.

PS: It might be worth to use a shell such as zsh with a git plugin to not be bitten by this thing in the future. It will immediately show that _deploy concerns a different repository.

Solution 6 - Git

I had this question twice, and it was always caused by the corruption of the git cache file at my local branch. I fixed it by writing the missing commit hash into that file. I got the right commit hash from the server and ran the following command locally:

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

Solution 7 - Git

Issue: Your branch is based on 'origin/master', but the upstream is gone.

Solution: git branch --unset-upstream

Solution 8 - Git

> This is the simplest solution you just put git branch --unset-upstream and if you type git status before you git push and after commit you see Your branch is based on 'origin/main', but the upstream is gone. (use "git branch --unset-upstream" to fixup) Hope it helps

picture for clarification

Solution 9 - Git

delete your local branch by following command

git branch -d branch_name

you could also do

git branch -D branch_name 

which basically force a delete (even if local not merged to source)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJatin GanhotraView Question on Stackoverflow
Solution 1 - GittorekView Answer on Stackoverflow
Solution 2 - GitElazarRView Answer on Stackoverflow
Solution 3 - GitAjay KotnalaView Answer on Stackoverflow
Solution 4 - GitsmremdeView Answer on Stackoverflow
Solution 5 - GitAnne van RossumView Answer on Stackoverflow
Solution 6 - Gituser1106400View Answer on Stackoverflow
Solution 7 - Gitreecha soniView Answer on Stackoverflow
Solution 8 - GitYakoutView Answer on Stackoverflow
Solution 9 - GitPravin BansalView Answer on Stackoverflow