1

I thought I had some problem with my git config,

every time i create a new branch I first have to set-upstream

git push --set-upstream sensorAtHome pull-down-to-refresh

where sensorAtHome is my project name and pull-down-to-refresh is branch name.

Actually I do not have to do it at my work place, I simple create branch do my work commit and push, I never have to set-upstream but for my projects at home when I push to GitHub.com I have to..

Is there something I am missing probably wrong with my workflow ?

Ciasto piekarz
  • 7,853
  • 18
  • 101
  • 197

1 Answers1

5

Assuming your work version of Git is pre-2.0 (your comment suggests it may be 1.8), that would be the reason your home Git (which 2.0 or later) and work Git (pre-2.0) behave differently.

In Git 2.0, the default value for push.default changed from matching to simple. Starting with Git 1.8.0, Git began producing warning messages about this. See Warning: push.default is unset; its implicit value is changing in Git 2.0 for details. Git version 2.8.0 dropped the warning.

Note that you may prefer current to simple. See "simple" vs "current" push.default in git for decentralized workflow. However, setting an upstream is useful: see Why do I need to do `--set-upstream` all the time? Read on for more background if you like.

Configuration

Whether as a result of this, or just because you decided you should configure it, you may have set your own value for push.default, either in any particular repository, or for your own personal all-repositories-wide --global setting. (Note that if you git config --global some setting, and then also git config the same setting locally in one specific repository, the local setting usually overrides. There are a few exceptions to this rule, e.g., for branch.master.fetch, but it tends to be unwise to set this to anything with --global!)

Matching, simple, and other modes

If you have not set it, or have set it explicitly to matching in your work setup but to simple in your home setup. the different actions of these two modes explain the issue. The behavior of matching is somewhat described in the accepted answer to Warning: push.default is unset; its implicit value is changing in Git 2.0, and much more in Default behavior of "git push" without a branch specified—but note that both of these describe what you get if you run:

git push sensorAtHome

or:

git push

but not:

git push sensorAtHome pull-down-to-refresh

More precisely, descriptions always start out talking about what happens when you push with no refspecs. (We'll get to refspecs in just a moment.)

There are actually five possible settings for push.default (although the new standard simple was only introduced in Git version 1.7.11, and there are still some people using Git 1.7). These five settings are nothing, current, upstream, simple, and matching.

The nothing setting is actually the simplest of all, but I tried it and found it annoying. :-) It forces you to name which branch you want to push. Because of this, we can mostly ignore it and only think about the other four.

The other four settings will intuit some branch or branches to push if you don't specify any branches. More precisely, these four settings intuit things if you leave out all the refspecs. But they can also affect what happens when you include some refspecs.

The git push syntax

The syntax for git push, if we ignore all the flags arguments, is:

git push <repository> <refspec> <refspec> ...

That is, the first argument after git push (also skipping any flags and flag arguments) is the repository. You can write out a full URL here, e.g.:

git push https://github.com/...

but it's usually much nicer to use a remote, which is a short name like origin, or in your case, sensorAtHome. For git push, the remote mostly just avoids having to type a long URL each time (for git fetch it also provides the origin/ part of the remote-tracking branch names).

After the repository argument, any remaining arguments are refspecs. The repository argument is actually optional, but if you want to give any refspec arguments at all, you must provide a repository argument first. But what exactly is a refspec? Why would we care about them?

Refspecs

The simplest form of a refspec is the one you are using here: it's just a branch name. You write:

git push someremote branch

and Git pushes the named branch. But refspecs are actually much more general.

First, a refspec starts off with two parts separated by a colon. For instance, instead of just saying branch, you can write:

git push someremote branch:branch

The name on the left is your name, and the name on the right is their name. Remember that when you run git push, you are using two Gits, with two different repositories. You are telling your Git to call up some remote Git. Once your Git has the other Git on the Internet-phone (via https or ssh or whatever), your Git sends some of your commits to their Git, and then your Git asks them to set their branches, usually based on the commits you just sent.

Since there are two Gits, there are two different branch names involved. Your branch might be named Fred, and theirs might be named Frederick-the-Great, for instance. Yours might be Zaphod and theirs might be Beeblebrox. Your branch is yours, and their branch is probably your upstream. There's no requirement that they have the same name—well, almost no requirement. And, if you literally spell out both parts, writing zaphod:beeblebrox or whatever, Git assumes you know what you are doing, and runs with that.

Things get pretty crazy if these names are not the same, though. It's much simpler if they match all the time. So, three of the four "interesting" settings—matching, current, and simple—try to make sure they stay the same. You just need to use your names, and your Git will try to ensure that their names match up.

The one setting that does not do this—the upstream mode—tells your Git to use your name on your side, and whatever you have configured as the upstream setting on their side. Obviously, for this to work, you must set an upstream. But this still leaves matching, current, and simple, and may leave you wondering what they are for.

The short answer is that matching is what Git did originally, but it turned out to be a mistake and you probably should never use it. You should use either simple or current instead. The simple setting is safer, but requires that you set an upstream. Again, for a bit more and to help you choose between them, see "simple" vs "current" push.default in git for decentralized workflow.

If you provide at least one refspec, the old matching setting works just like current. Your Git takes the refspec or refspecs (i.e., branch name) you provided—and remember, this is only for when you didn't write local-name:remote-name, so there's just a local name—and has their Git create or update a branch with the same name, whether or not your branch has an upstream set. But if you leave out all the refspecs, matching tells your Git to ask their Git about all their branches, and look up all your branches, and match up the names. Wherever the names are the same, your Git sends your commits to their Git, and asks them to set their same-named branch.

For most people, at most times, this difference is small. You have your master, and maybe your develop and a feature branch or two. You git fetch to pick up new stuff, work for a while, and git push to send what you wrote. Your Git asks their Git to update master and develop and your feature branches. If you were not supposed to be working on master, and you didn't work on master—just on develop—there's nothing in your master for your Git to push, so there is no problem. Even if someone else pushed something new to the other Git's master, you just get part of your push rejected with an error: your develop changes get pushed and your attempt to remove their new commits from their master meets with an error.

But look: you just asked your Git to delete their new commits from their master. That's a bad sign, if nothing else. And, if you did some experimental work on a feature branch, and it's not actually ready to push yet and you plan to fix some stuff and rebase some bad commits away in that feature branch, you may have just accidentally pushed both develop and that feature branch.

It's just bad all around. The current setting is a whole lot like the matching setting, but it pushes only one branch by default, which is the one you have checked out now.

The simple setting is just like the current setting, but adds one more safety belt: the current branch needs to have its upstream set, to a branch of the same name in the other Git.

Refspecs are more general than just branches

For completeness, I want to mention a few more things about refspecs. One is that they don't have to name branche: you can also name tags. Your Git will generally figure out which one you mean, provided you don't use the same name for both a tag and a branch (don't do this—Git has a defined set of rules for what happens, but they are weird and conflict-y and will confuse you). You can spell out the "full name" of any reference: refs/heads/master, refs/tags/v1.2, and so on. You can leave out the local name, by writing :delete, which asks their Git to delete a branch or tag or other reference. Last, you can set a per-refspec force flag.

Summary

These are the five possible settings for push.default:

  • nothing: you must include at least one refspec argument (which forces you to include the remote part as well). You can't really go wrong with this setting; the problem is that it's quite annoying, i.e., you can't just go right either.
  • matching: this is the old, pre-2.0 Git behavior. It can push too many branches, so don't use it unless you're really stubborn. :-)
  • current: this is the better-behaved variant of matching.
  • simple: this is the same as current with the added safety-check that your branch needs to have an upstream set, with the same basic branch name. The safety-check can be slightly annoying: it forces you to set the upstream. Setting the upstream has value other than just making simple happy, though, so this is really the best push.default for most people most of the time.
  • upstream: this is for the slightly-crazy-making case where, for some reason, you have to name your branch fred even though the upstream is ginger, or whatever. It's kind of a more permissive variant of simple: you still have to set the upstream, but you can set it to take a trip on the crazy train.
Community
  • 1
  • 1
torek
  • 448,244
  • 59
  • 642
  • 775
  • Where are these possible settings located on ḍisk ? – Ciasto piekarz Feb 19 '17 at 19:45
  • `git config --global` writes to your global settings but the location varies depending on system. You can run `git config --global --edit` to bring up your preferred editor on all your global settings. The local, per-repository settings are in `.git/config`, but again, just use `git config --edit` if you want to work on them in your editor. – torek Feb 19 '17 at 19:48
  • That I am aware of I was thinking maybe I can have look at the code of these functions ! If they really are open ! – Ciasto piekarz Feb 19 '17 at 19:49
  • @Ciastopiekarz: In that case, you don't have `simple` mode there, since it was new in 1.7.11. – torek Feb 20 '17 at 07:27