408

I created a local branch for testing Solaris and Sun Studio. I then pushed the branch upstream. After committing a change and attempting to push the changes:

$ 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

Why do I have to do something special for this?

Is there any reasonable use case where someone would create <branch>, push the <branch> to remote, and then claim a commit on <branch> is not supposed to be for <branch>?


I followed this question and answer on Stack Overflow: Push a new local branch to a remote Git repository and track it too. I'm guessing it's another instance of an incomplete or wrong accepted answer. Or, it's another instance of Git taking a simple task and making it difficult.


Here's the view on a different machine. The branch clearly exists, so it was created and pushed:

$ 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
5
  • 2
    Possible duplicate of Why do I need to do `--set-upstream` all the time? Commented May 31, 2017 at 20:12
  • 3
    Thanks @Alexi. Unfortunately, the cited dup does not explain the ridiculous use case that is being represented by default. (Those are not rhetorical questions. I'm genuinely interested in the reason for the UX design).
    – jww
    Commented May 31, 2017 at 20:43
  • 6
    Note that this is configurable. If you do git config --add push.default current, then git push will automatically create the branch in the remote repo if necessary.
    – Gogowitsch
    Commented Jun 8, 2019 at 12:05
  • 13
    For those who want to stop seeing this message forever, avoid the other answers and comments and just run git config --global push.default current
    – Andy Ray
    Commented Oct 27, 2021 at 4:33
  • 1
    With the newest version of Git 2.37.0, you can run just "git push" to push new branches. No more "--set-upstream origin". Enable with: git config --global --add --bool push.autoSetupRemote true Commented Jul 20, 2022 at 4:49

9 Answers 9

585

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


The answer to the question you asked—which I'll rephrase a bit as "do I have to set an upstream"—is: no, you don't have to set an upstream at all.

If you do not have upstream for the current branch, however, Git changes its behavior on git push, and on other commands as well.

The complete push story here is long and boring and goes back in history to before Git version 1.5. To shorten it a whole lot, git push was implemented poorly.1 As of Git version 2.0, Git now has a configuration knob spelled push.default which now defaults to simple. For several versions of Git before and after 2.0, every time you ran git push, Git would spew lots of noise trying to convince you to set push.default just to get git push to shut up.

You do not mention which version of Git you are running, nor whether you have configured push.default, so we must guess. My guess is that you are using Git version 2-point-something, and that you have set push.default to simple to get it to shut up. Precisely which version of Git you have, and what if anything you have push.default set to, does matter, due to that long and boring history, but in the end, the fact that you're getting yet another complaint from Git indicates that your Git is configured to avoid one of the mistakes from the past.

What is an upstream?

An upstream is simply another branch name, usually a remote-tracking branch, associated with a (regular, local) branch.

Every branch has the option of having one (1) upstream set. That is, every branch either has an upstream, or does not have an upstream. No branch can have more than one upstream.

The upstream should, but does not have to be, a valid branch (whether remote-tracking like origin/B or local like master). That is, if the current branch B has upstream U, git rev-parse U should work. If it does not work—if it complains that U does not exist—then most of Git acts as though the upstream is not set at all. A few commands, like git branch -vv, will show the upstream setting but mark it as "gone".

What good is an upstream?

If your push.default is set to simple or upstream, the upstream setting will make git push, used with no additional arguments, just work.

That's it—that's all it does for git push. But that's fairly significant, since git push is one of the places where a simple typo causes major headaches.

If your push.default is set to nothing, matching, or current, setting an upstream does nothing at all for git push.

(All of this assumes your Git version is at least 2.0.)

The upstream affects git fetch

If you run git fetch with no additional arguments, Git figures out which remote to fetch from by consulting the current branch's upstream. If the upstream is a remote-tracking branch, Git fetches from that remote. (If the upstream is not set or is a local branch, Git tries fetching origin.)

The upstream affects git merge and git rebase too

If you run git merge or git rebase with no additional arguments, Git uses the current branch's upstream. So it shortens the use of these two commands.

The upstream affects git pull

You should never2 use git pull anyway, but if you do, git pull uses the upstream setting to figure out which remote to fetch from, and then which branch to merge or rebase with. That is, git pull does the same thing as git fetch—because it actually runs git fetch—and then does the same thing as git merge or git rebase, because it actually runs git merge or git rebase.

(You should usually just do these two steps manually, at least until you know Git well enough that when either step fails, which they will eventually, you recognize what went wrong and know what to do about it.)

The upstream affects git status

This may actually be the most important. Once you have an upstream set, git status can report the difference between your current branch and its upstream, in terms of commits.

If, as is the normal case, you are on branch B with its upstream set to origin/B, and you run git status, you will immediately see whether you have commits you can push, and/or commits you can merge or rebase onto.

This is because git status runs:

  • git rev-list --count @{u}..HEAD: how many commits do you have on B that are not on origin/B?
  • git rev-list --count HEAD..@{u}: how many commits do you have on origin/B that are not on B?

Setting an upstream gives you all of these things.

How come master already has an upstream set?

When you first clone from some remote, using:

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

or similar, the last step Git does is, essentially, git checkout master. This checks out your local branch master—only you don't have a local branch master.

On the other hand, you do have a remote-tracking branch named origin/master, because you just cloned it.

Git guesses that you must have meant: "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."

This happens for every branch you git checkout that you do not already have. Git creates the branch and makes it "track" (have as an upstream) the corresponding remote-tracking branch.

But this doesn't work for new branches, i.e., branches with no remote-tracking branch yet.

If you create a new branch:

$ git checkout -b solaris

there is, as yet, no origin/solaris. Your local solaris cannot track remote-tracking branch origin/solaris because it does not exist.

When you first push the new branch:

$ git push origin solaris

that creates solaris on origin, and hence also creates origin/solaris in your own Git repository. But it's too late: you already have a local solaris that has no upstream.3

Shouldn't Git just set that, now, as the upstream automatically?

Probably. See "implemented poorly" and footnote 1. It's hard to change now: There are millions4 of scripts that use Git and some may well depend on its current behavior. Changing the behavior requires a new major release, nag-ware to force you to set some configuration field, and so on. In short, Git is a victim of its own success: whatever mistakes it has in it, today, can only be fixed if the change is either mostly invisible, clearly-much-better, or done slowly over time.

The fact is, it doesn't today, unless you use --set-upstream or -u during the git push. That's what the message is telling you.

You don't have to do it like that. Well, as we noted above, you don't have to do it at all, but let's say you want an upstream. You have already created branch solaris on origin, through an earlier push, and as your git branch output shows, you already have origin/solaris in your local repository.

You just don't have it set as the upstream for solaris.

To set it now, rather than during the first push, use git branch --set-upstream-to. The --set-upstream-to sub-command takes the name of any existing branch, such as origin/solaris, and sets the current branch's upstream to that other branch.

That's it—that's all it does—but it has all those implications noted above. It means you can just run git fetch, then look around, then run git merge or git rebase as appropriate, then make new commits and run git push, without a bunch of additional fussing-around.


1To be fair, it was not clear back then that the initial implementation was error-prone. That only became clear when every new user made the same mistakes every time. It's now "less poor", which is not to say "great".

2"Never" is a bit strong, but I find that Git newbies understand things a lot better when I separate out the steps, especially when I can show them what git fetch actually did, and they can then see what git merge or git rebase will do next.

3If you run your first git push as git push -u origin solaris—i.e., if you add the -u flag—Git will set origin/solaris as the upstream for your current branch if (and only if) the push succeeds. So you should supply -u on the first push. In fact, you can supply it on any later push, and it will set or change the upstream at that point. But I think git branch --set-upstream-to is easier, if you forgot.

4Measured by the Austin Powers / Dr Evil method of simply saying "one MILLLL-YUN", anyway.

22
  • 6
    If the common case is to {create branch/push branch/use branch}, then shouldn't the result of Push a new local branch to a remote Git repository and track it too be something that actually works? And if someone wants {create branch/push branch/don't use branch}, then shouldn't they have to do something special, like --set-upstream /dev/null? Why is the burden pushed onto the common case? I really don't understand some of these engineering and usability decisions.
    – jww
    Commented Jun 12, 2016 at 5:08
  • 3
    @VonC: right, that's the point of git push -u, but it really seems like git push -u should be the default, or at least the default if there is no upstream yet, and there should be a git push --no-set-upstream when there isn't currently an upstream and you want to keep it that way (for whatever incomprehensible reason :-) ).
    – torek
    Commented Jun 12, 2016 at 5:09
  • 5
    " You keep asking questions like this because, I think, you've written off Git as "really obnoxious"." Please keep this kind of speculation to yourself. I came across this question because I also keep asking myself these kinds of questions. I'm not the world's best UX designer, but even I recognize that the default behavior in this particular scenario could be better. Commented Jun 30, 2016 at 21:03
  • 15
    Note that this is configurable. If you do git config --add push.default current, then git push will automatically create the branch in the remote repo if necessary.
    – Gogowitsch
    Commented Jun 8, 2019 at 12:03
  • 1
    @FrankPuck If your Gt did not ask you to set an upstream, why did you read a question asking why Git asked you to set an upstream? :-) In any case, Git is (a) somewhat old, with many versions, only some of which ask you to set an upstream; and (b) very configurable, so that you can set it so that it does not ask you to set an upstream. If it is not asking you to set an upstream, you don't have to set an upstream.
    – torek
    Commented May 22, 2020 at 17:23
160

The difference between

git push origin <branch>

and

git push --set-upstream origin <branch>

is that they both push just fine to the remote repository, but it's when you pull that you notice the difference.

If you do:

git push origin <branch>

when pulling, you have to do:

git pull origin <branch>

But if you do:

git push --set-upstream origin <branch>

then, when pulling, you only have to do:

git pull

So adding in the --set-upstream allows for not having to specify which branch that you want to pull from every single time that you do git pull.

2
  • 5
    @FrankPuck this is Git, it professes to be usable for offline use, but without Google or SO it's impossible to use as soon as you leave the "trodden path". Briefly explained: --set-upstream in git push (as opposed to git branch with --set-upstream-to) is what -b is to git checkout (as opposed to git branch or nowadays git switch -c). This is insanity throughout and you shouldn't expect anything less. Of course with git push set-upstream you'll want to specify remote branch whereas with git branch --set-upstream-to you use remote/branch (also known as commreftreeish 😉). Commented Oct 6, 2020 at 15:53
  • 4
    @FrankPuck the difference between the two is that git was created to be a distributed version control system without a central source of truth like CVS and SVN. The proliferation of centralized repositories such as GitHub have turned git into a copy-of-a-centralized-vcs model. This is why the push behavior did not include a single upstream. You should be able to push a change to whichever repository needed it. A friend's, a central server, another machine you own, etc. It is a way to share changesets, not a way to centralize versions.
    – Josh J
    Commented Jul 14, 2021 at 17:58
104

You can configure git to do this automatically:

git config --global push.default current

This is what you want in 99% of the case anyway in my experience.

4
  • Thank you, I always forget this. I made a gist if anyone needs to fork to remember gist.github.com/jottenlips/f1ad4c53c287e263caea420d7f8f8e20 Commented Aug 17, 2022 at 18:45
  • 1
    I have been using this option, but it just moves the problem down the line - when the remote branch is created this way, you can't use git pull - it will prompt you to use git branch --set-upstream-to=origin/<branch> your-branch, without even an easy to copy example.
    – MightyPork
    Commented Aug 29, 2022 at 12:26
  • 1
    That can be a problem sure. But I find that 99% of the time I create a branch to push a PR and then it's merged, making it irrelevant.
    – boxed
    Commented Oct 13, 2022 at 7:02
  • 1
    This is truly what the OP was getting at. The "reason" they have to --set-upstream-to can be described by a novel, or it can be described by "you didn't git config --global push.default current" I prefer the latter Commented Jul 22, 2023 at 22:21
32

With the Git 2.37.0 version, there is no need to use --set-upstream origin. You can use git push directly after enabling push.autoSetupRemote using the following:

git config --global --add --bool push.autoSetupRemote true

Source: James Ide's tweet

Hope this helps!

2
  • 1
    Thanks, this is the answer I was looking for! This makes git pull after git push just work if you have push.default = current, it just assumes the remote branch and local branch have the same name. This is so much better than having to write the remote branch each time (the default) or than any of the other solutions posted. Thanks! Commented Sep 2, 2022 at 16:20
  • ooooh I was not aware of this, many thanks! Should be ranked higher here! 🙏🏼
    – rsenna
    Commented Jan 29 at 14:42
25

A basically full command is like git push <remote> <local_ref>:<remote_ref>. If you run just git push, git does not know what to do exactly unless you have made some config that helps git to make a decision. In a git repo, we can setup multiple remotes. Also we can push a local ref to any remote ref. The full command is the most straightforward way to make a push. If you want to type fewer words, you have to config first, like --set-upstream.

23

The -u flag is specifying that you want to link your local branch to the upstream branch. This will also create an upstream branch if one does not exist. None of these answers cover how i do it (in complete form) so here it is:

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

So if your local branch name is coffee

git push -u origin coffee
1
  • 5
    -u is just a shortcut for --set-upstream. Despite the upvotes, It's not clear at all how this answer remotely answers the OP's question. In the realm of "how I do it" recipes, boxed's answer below is much more useful, as it avoids typing the boilerplate every time. Commented Jan 18, 2022 at 7:31
14

My understanding is that -u or --set-upstream allows you to specify the upstream (remote) repository for the branch you're on, so that next time you run git push, you don't even have to specify the remote repository.

Push and set upstream (remote) repository as origin:

$ git push -u origin

Next time you push, you don't have to specify the remote repository:

$ git push
10

tl;dr If you want to not think about this but also not modify your configs:

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

0
0

In my scenario, the complication differed.

Within the overarching ~/.ssh directory, a pivotal file named config resides, which you can either locate or generate.

When managing multiple SSH keys and necessitating distinct ones for Git, the following code proves invaluable:

Host github.com
  IdentityFile ~/.ssh/id_rsa

Essentially, this snippet facilitates the utilization of a custom SSH key. In my configuration, I originally specified id_git as the IdentityFile.

However, I later replaced it with the one specified in my GitHub account settings under Account Settings > SSH keys.

Subsequently, all functionalities resumed seamlessly.

Not the answer you're looking for? Browse other questions tagged or ask your own question.