Posted By: Anonymous
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.
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.
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 Why do I have to "git push –set-upstream origin <branch>"?
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
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
origin, and branches named
linklog, and so on on
(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
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
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.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”,
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.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
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).
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.merge set, to
refs/heads/master. But then your
origin remote changed its name from
source. To match, I believe you also changed your local name from
source. This changed the names of your settings, from
branch.source.remote and from
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.
git 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
git config. If you just want to set the upstream to
origin/source the only part that has to change is
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”.