0

I did

git checkout -b NEW_BRANCH

Everywhere it is being mentioned, that in order to push this to the remote, one has either to tell the push command some additional information

git push origin NEW_BRANCH

, or one has to associate the local branch with a remote branch

git branch --set-upstream origin NEW_BRANCH

I don't understand the need for either. In other words, I don't understand the effects of the additional commands? What are they? Or what would happen, if one just says

git push

? In either of the above commands, does NEW_BRANCH refer to the local branch name or to the remote branch name (if there is a difference)?

Cœur
  • 37,241
  • 25
  • 195
  • 267
  • 2
    Possible duplicate of [Why do I need to do \`--set-upstream\` all the time?](https://stackoverflow.com/questions/6089294/why-do-i-need-to-do-set-upstream-all-the-time) – Makoto Dec 10 '18 at 16:20
  • Also related: https://stackoverflow.com/q/37770467/1079354 – Makoto Dec 10 '18 at 16:21
  • @Makoto -- the question you mentioned is regarding git pull –  Dec 10 '18 at 16:24
  • Possible duplicate of [What is the difference between git push origin and git push origin master](https://stackoverflow.com/questions/12462481/what-is-the-difference-between-git-push-origin-and-git-push-origin-master) – phd Dec 10 '18 at 16:53

3 Answers3

0

Because you have not associated your local branch with a remote branch yet.

Note that branch naming on the remote and local side do not need to be 1-on-1 the same.

In your local state, your branches are "linked" to upstream branches. It just needs to "make that link".

To see the state of which branch is "linked" (tracking) which remote branch, you can use (in case your remote is called origin):

git remote show origin
marcolz
  • 2,880
  • 2
  • 23
  • 28
0

I don't understand the need for either. In other words, I don't understand the effects of the additional commands? What are they?

I assume you're talking about this command: git push <remote-name> <branch-name>. You also can just do git push.

git is a distributed version control system. As such, you may have more than one remote (or even zero remotes). Colloquially, origin is the name that's given to the remote after you clone (you can rename it, or remove it, doesn't matter). Hopefully that convinces you why you (might) need to specify the remote. If you have 7 remotes, git can't know which one you want to push to. origin is the default remote if you just do git push.

git also doesn't know which branch you want to push. You can have many branches. So, it's logical you might want to push some and not others, hence the reason for the <branch-name> argument (technically a refspec, which is a superset of branches). As a shortcut, you can specify HEAD as the commit you want to push (HEAD is a pointer to the current commit). So, you can say git push origin HEAD, which is especially convenient if you have a long branch name. Again, git push will push the current branch by default assuming it has a matching upstream branch. If not, you have to either push it by hand (git push origin HEAD) which will create the upstream branch, and then barebones git push will work henceforth for that branch, or you can also manually set it as an upstream branch --set-upstream.

Mandatory docs link

HTH.

Matt Messersmith
  • 12,939
  • 6
  • 51
  • 52
0

There are multiple parts to the right answer, which is why this is so confusing. To understand this properly, let's start by defining some terms:

  • A remote is a simple name, like origin or upstream. This name lets Git store a URL—technically, one or more URLs, but usually just one—so that instead of typing out https://user@host.dom.ain/some/fairly/long/path/to/some/other/repo.git or similar, you can just type origin.

    Git has one built in, more or less standard, remote named origin, which is created by git clone and automatically remembers the URL you used when you ran git clone.

  • A reference or ref is something you use to refer to commits, such as a branch name or tag name like master or develop. References have long forms: master is really refs/heads/master, for instance. Most of the time you can just use the short form and not worry about this, but the long form is there, and is what Git uses internally, for handling tricky cases like if you accidentally make a tag master. (Don't do that on purpose, but if you do it by mistake, the long form will always let you fix things.)

  • A refspec is, essentially, a pair of references separated by a colon : character. For instance, master:master is a refspec, as is refs/heads/develop:refs/heads/develop. But that's a more complicated form of refspec: you can drop the colon and second name, in a lot of cases, in which case it looks like a reference.

What git push needs is, in order, one remote followed by one or more refspecs.

This in turn means the answer to your question:

git push origin NEW_BRANCH

... does NEW_BRANCH refer to the local branch name or to the remote branch name (if there is a difference)?

is actually a bit more complicated, because that NEW_BRANCH isn't a branch name after all, it's a refspec. It just looks like a branch name!

What git push does is to call up another Git. The other Git "lives" (or at least answers the Internet-phone-call your Git makes) at the URL, which your Git finds by looking up the remote. Then the two Gits have a conversation, in which your Git finds out what commits their Git has, offers their Git new commits if needed, and finally, asks their Git to set some of their branch names to remember some commits found in your Git repository. (By this point, they have those commits as well, if they didn't before, thanks to the in-between conversation.)

So the NEW_BRANCH refspec that you give here is actually both names. When you use the form that has the colon in it, you can use two different names, or even use a raw hash ID on your side:

git push origin master:somebranch

which has your Git offer your new commits and then set their somebranch to point to the same commit that your master points to, or:

git push origin a123456:refs/heads/somebranch

which has your Git make sure they have commit a123456... and then set their somebranch to point to that particular commit.1

I don't understand the need for [remote and refspec]

Well, in fact, often you don't need them. You might think that this would mean always, but it doesn't, for multiple historical reasons.

First, Git didn't always have remotes at all, so in place of the remote name, you can just write out a URL.2 If you don't use either a remote or a URL, Git will figure out a default (often origin). But if you need to list a refspec, you must provide either a remote or a URL, because the remote-or-URL has to go in that position in the arguments.

Second, Git used to default to pushing multiple branches at once using a rather overly enthusiastic default refspec. Today, it defaults to pushing one branch using a sane refspec. This ought to—and does!—make it not need the refspec, but only once some condition is met. And, you can change this default, using push.default; if you do, that changes the conditions under which you can omit the refspec(s), and hence the remote name.

Using today's default push.default of simple, Git will automatically figure out and use the correct remote and refspec if:

  1. The current branch has an upstream set, and
  2. The upstream names a branch of the same name on the remote.

The remote here can be any of your remotes: if branch xyz has an upstream of foo/xyz, the remote is foo and the branch on foo is xyz so conditions 1 and 2 are both met and git push will do the right thing.

When you first create a new branch, its upstream setting—if any—is determined by how you create that branch. Using git checkout -b name gives you a new branch name that has no upstream by default. Using git checkout --track remote/name gives you a new branch name that has remote/name as its upstream, and there are various other options that do set some upstream.


1If you use this form, you usually have to spell out the full reference name. The reason is that when you use the shortened names, like git push origin x234, Git scans through your references to figure out whether, say, x234 is a branch name or a tag name. That lets your Git tell their Git: set your refs/heads/x234 (branch) or set your refs/tags/x234 (tag).

2In those really old versions of Git, you always had to supply a URL. As you might imagine, this was kind of painful. That led to several experiments, which ultimately produced the idea of a remote, and once there was a standard remote named origin, that allowed you to omit the remote entirely, as long as you could also omit all the refspecs.

The experiments are all still supported as well. You can use work:foo plus an insteadOf entry to map work: to a host name and optional path therein.

torek
  • 448,244
  • 59
  • 642
  • 775