1

I have a question about git... supposed I cloned my project with this code

git clone ssh://git@<my-project.git>

and then executed a line like this to add remote upstream link

git remote add upstream ssh://git@<my-project.git>

When I try to run this line, I have verified that my upstream was set

$ git remote -v
origin  ssh://git@<my-project.git> (fetch)
origin  ssh://git@<my-project.git> (push)
upstream        ssh://git@<my-project.git> (fetch)
upstream        ssh://git@<my-project.git> (push)

So I created a new branch taken from the master

git checkout -b sample-branch master
Switched to a new branch 'sample-branch'

But when I am trying to push my local branch, I am getting below error.

git push

fatal: The current branch sample-branch has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin sample-branch

Maybe I am thinking that since I have add an upstream already that my local branch does not need to set my upstream or I maybe thinking wrong? I have to execute the line above first before I can execute

git push 

on succeeding commands.

Mark Estrada
  • 9,013
  • 37
  • 119
  • 186

3 Answers3

2

For the TL;DR version, see VonC's answer.

git remote add adds a remote. Remotes can have any name you like, though by convention, origin is the first one, and upstream is often the second. But normally if you added a second remote it would have a different URL, not the same URL. You only need more than one remote if you talk to multiple different Git repositories, each at different URLs.

Confusingly, the remote named upstream (assuming you have one) is not an upstream, it's just a remote.

The term upstream, when applied to a branch name, refers to what is internally a two-part setting (as VonC said). Every branch name, such as master or feature, can have one upstream, or no upstream. Typically the upstream of master would be origin/master and the upstream of feature would be origin/feature. If you did have multiple remotes, and called the second one upstream, you could set the upstream of branchX to upstream/branchX.

So: the upstream of a branch is some other name, typically one starting with the name of a remote. Git uses this setting to remember "that's where I fetch/pull from" and "that's where I push to". This name must actually exist, though, and that's where things really get confusing.

So I created a new branch taken from the master

git checkout -b sample-branch master
Switched to a new branch 'sample-branch'

Technically, this creates a new branch name in your own Git repository, named sample-branch. The commit hash ID selected by this new branch name is the same as the commit hash ID selected by the existing name master (also a branch name).

When you use this kind of git checkout command, your Git will set the upstream of the new branch to the name of the other branch if it is, say, origin/sample-branch. But you probably don't have an origin/sample-branch. This name would only exist if the Git over at origin—at the URL stored in the remote named origin, that is—has a branch named sample-branch, and your Git had seen this and copied it over. Since you didn't use origin/sample-branch here—and if you did, it would just fail anyway—your Git didn't set an upstream for the new branch.

You need to do something eventually about this. There's no need to do this right away! You can do it whenever you like. But eventually, you do need to do it. There are two steps involved:

  1. You must get the other Git, the one over on origin, to create a branch named sample-branch. When you get that Git to create its sample-branch, your Git can now copy that to your origin/sample-branch, so that your origin/sample-branch exists.

  2. Once your origin/sample-branch exists, you need to get your Git to set origin/sample-branch as the upstream for sample-branch.

You can do this two step process with two separate Git commands, and in the ancient past, you had to do it that way. With modern Git versions, though, one command suffices. That one command is git push -u origin sample-branch.

What this does is:

  1. Have your Git call up their Git (the Git at origin) using the URL stored in the name origin.

    Your Git offers their Git any new commits and other objects required to complete the overall task. Your Git will then send commits and their contained files if needed. Once they have everything required, your Git then sends them a polite request: Please, if it's OK, create or update your name sample-branch so that it identifies a particular commit. The particular commit your Git recommends here is the same commit that your name sample-branch identifies.

    If they accept this request, that creates their sample-branch. Since your Git now sees that their Git has sample-branch, your Git creates your origin/sample-branch to remember this.

  2. Now that your Git has origin/sample-branch, your git push -u automatically invokes git branch --set-upstream-to=origin/sample-branch sample-branch.

If you wish, for some reason, to do this the old two-step way, run:

git push origin sample-branch:sample-branch

(the two names here separated by the colon tell your Git what to tell their Git). Then, when that has succeeded, run:

git branch --set-upstream-to=origin/sample-branch sample-branch

Obviously the single git push -u command is shorter and easier.

torek
  • 448,244
  • 59
  • 642
  • 775
1

Setting an upstream remote differs from setting an upstream branch (which is a remote+a remote branch name): your second remote should not be needed at all.
See "Upstream (as related to) Tracking".

Try first:

 git push -u origin sample-branch

Then git branch -avv: you will see your branch associated to a remote one.

A git push will then work for the next commits publication.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
0

The two existing answers to into a lot of theory as to why, by default, you need to do this other thing, because your question implied a lack of understanding regarding the difference between the upstream remote, and the upstream tracking branch for your local branch.

In my opinion the shorter/better answer to your question, however, is that you shouldn't need to.

If you're running git 2.37+ and you run the following commands, git will behave the way you, and most people in my experience, would expect it to:

git config --global branch.autoSetupMerge simple
git config --global push.autoSetupRemote true

When you branch locally with the same name as a remote branch, the existing remote upstream will be set as the tracking branch, and git pull and git push will work as you expect (as they do now).

When you branch locally with a different name, no tracking branch will initially be set - git pull will not work yet. When you first git push, the new remote branch you are pushing will be set up as your new remote tracking branch, and git pull and git push will work as you expect - pushing and pulling to/from the remote branch you created in your first "push".

I don't know whether these configuration options will ever become the defaults, but in my opinion they would avoid a substantial amount of consternation from a large proportion of git users, especially as they start to use it.

Tao
  • 13,457
  • 7
  • 65
  • 76