1

I had a git repository with a remote branch origin/master.

I needed the repository to track a branch on another remote git server m1/master. So I added the new remote server using the git remote add command.

So I performed the following command:

$ git branch -a
* master
  remotes/m1/master
  remotes/origin/master

So checking out the m1 master branch

$ git checkout -b m1-master m1/master
Branch mht-m1 set up to track remote branch master from m1.
Switched to a new branch 'm1-master'

Now doing a git push

$ git push
Total 0 (delta 0), reused 0 (delta 0)
To git@<m1 server>/repo.git
* [new branch]      m1-master -> m1-master 

Why does git push on the tracking branch m1-master create a new remote branch, instead of pushing changes to the existing remote branch that it tracks? What am I missing here?

PS: Using git version 1.8.4.2

Nithin
  • 2,223
  • 4
  • 21
  • 29

2 Answers2

2

Because of the push.default configuration option Git obeys. To cite the git-config(1) manual page:

push.default

Defines the action git push should take if no refspec is given on the command line, no refspec is configured in the remote, and no refspec is implied by any of the optionsgiven on the command line. Possible values are:

  • nothing - do not push anything.

  • matching - push all branches having the same name in both ends. This is for those who prepare all the branches into a publishable shape and then push them out with a single command. It is not appropriate for pushing into a repository shared by multiple users, since locally stalled branches will attempt a non-fast forward push if other users updated the branch.

    This is currently the default, but Git 2.0 will change the default to simple.

  • upstream - push the current branch to its upstream branch. With this, git push will update the same remote ref as the one which is merged by git pull, making push and pull symmetrical. See "branch.<name>.merge" for how to configure the upstream

  • simple - like upstream, but refuses to push if the upstream branch’s name is different from the local one.

    This is the safest option and is well-suited for beginners. It will become the default in Git 2.0.

  • current - push the current branch to a branch of the same name.

The simple, current and upstream modes are for those who want to push out a single branch after finishing work, even when the other branches are not yet ready to be pushed out. If you are working with other people to push into the same shared repository, you would want to use one of these.

So I'd say for some reason you have push.default set to current or upstream and so mere running git push sends to the default remote your currently checked out branch trying to update there a ref with the same name (possibly creating it).

You could verify if this is true by running

git config --get-all push.default

in your repository.

kostix
  • 51,517
  • 14
  • 93
  • 176
  • Setting to `upstream` should push to the tracking name, i.e., `master`. I think only `current` should behave that way... – torek Nov 15 '13 at 15:45
  • the command `git config --get-all push.default` gives me `current`. So what should I do now? – Nithin Nov 15 '13 at 15:45
  • How to chaange the setting? – Nithin Nov 15 '13 at 16:03
  • @torek, yes, you're correct: I did not pay enough attention to how the OP created the local branch being discussed. – kostix Nov 15 '13 at 16:19
  • 1
    @Nithin, depends on *where* you want to change the setting: Git has three levels of setting (from lowest priority to highest): system, global and repository. Depending on the level you'd like to affect, you should pass `--system`, `--global` or `--local` (or nothing, it's the default) to `git config`. In the simplest case (repository setting), just run `git config push.default matching`. To change a global setting, run `git config --global push.default matching` etc. – kostix Nov 15 '13 at 16:22
2

OK, first, some terminology:

  • A (regular, ordinary, local) branch is something like master.

  • A "remote branch" like origin/master is something stored in your local repository, to remember where, on the remote, the remote had its own (local) branch pointing.

    A "remote branch" gets updated when you contact the remote (typically on fetch and push). At that time, your local git finds out what branches they have, and updates these.

  • A "tracking branch" is a local branch that records two items: a "remote", typically a name like origin, and another "merge" name. For instance, if your local branch master is a tracking branch, it may be configured with branch.master.remote = origin and branch.master.merge = master. Annoyingly, you can't always just string these together (you have to map through remote.origin.fetch to be completely correct with this) but in general this means that your local master is "tracking" origin/master".

You can't1 create a "remote branch" locally. You have to fetch or push to/from the remote. If that remote has a local branch named X, your git then records the remote's idea of that branch, using the origin/X style name.

So, what's going on here? Well, you did this:

$ git checkout -b m1-master m1/master

That creates a local branch named m1-master. (This local branch is also a tracking branch, but that's only partly relevant here, because of the push.default setting below.)

Then, you did this:

$ git push

(with no remote name and no refspecs after push). Git uses the default remote, which turns out to be m1 because of the tracking. Next though, git uses a default refspec, based on push.default and/or other git config items.

As of git 1.8.4.2 the "default push.default" is matching. This would not create a new branch (but also won't push anything unless there's an m1-master there). You have it set to current, which means: "please update or create, on the remote, the current branch, using its current name." The current branch is m1-master, so that was created.

Change push.default to upstream to fix this:

git config push.default upstream

(Also, see "Warning: push.default is unset; its implicit value is changing in Git 2.0" for various other options.)


1Well, you can do it with git update-ref or manual poking about in your .git directory. :-) Just, not with "normal" user commands.

Community
  • 1
  • 1
torek
  • 448,244
  • 59
  • 642
  • 775
  • I dont know why you said `This local branch is also a tracking branch, but that's irrelevant here.`. This is relevant and exactly the reason why I used the command. This branch does track `m1/master`. Which is what i want. What confuses me is it created the branch on the tracked remote server `m1` but it did not push to the tracked branch, instead it created a new branch on `m1` with the same name as the local branch. The `m1-master` was not created in `origin` but in `m1` – Nithin Nov 15 '13 at 15:59
  • It's irrelevant when `push.default` is set to `current`! (I.e., push won't look at what it's tracking.) – torek Nov 15 '13 at 16:01
  • Ok...You meant to say that its irrelevant to `push` with the current setting. It was relevant to pull, which is what I wanted to say. – Nithin Nov 15 '13 at 16:07
  • It should, yes. (I have not experimented much with `push.default` settings, I mostly try to be explicit these days and `git push remotename branchname`.) Also I need to fix the `origin` bit in the answer above... – torek Nov 15 '13 at 16:25
  • Setting `push.default` to `upstream` fixed the issue. Please add that to the answer and I ll mark it as the answer. `upstream` seems to be the only mode that would use the tracking branch during push. `simple` needs the local and remote branch names to be the same. – Nithin Nov 15 '13 at 19:30
  • There, I think we've got this one pinned down properly now. :-) – torek Nov 15 '13 at 19:41