Git pushed master instead of my branch. Why?

1.7k views Asked by At

I'm figuring out working with branches in git. At the time I had unrelated commits in master I wasn't quite ready to push, but I had to do a bug fix. I didn't want to create a new repo just to do a small bug fix, so I created a branch based off of origin/master

git checkout -b example origin/master

Its my understanding this creates a branch based off of the origin/master branch, and switches to the example branch.

I then went and did my fix, committed it, and tested it.

$ git status
On branch example
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

nothing to commit, working directory clean

I then went to push it to master.

$ git push origin master

but instead of it pushing the commit in the example branch, I found this instead

    $ git status
    On branch example
    Your branch and 'origin/master' have diverged,
    and have 1 and 3 different commits each, respectively.
        (use "git pull" to merge the remote branch into yours)

    nothing to commit, working directory clean

I don't understand why

2

There are 2 answers

0
torek On BEST ANSWER

The syntax for git push is a bit obscure, but easy enough to explain for the particular case you are using:

$ git push remote refspec

The remote you named is the typical one, origin; this lets your git find the URL for their git. That part is all good so far.

The problem occurs with the refspec you gave, master.

You might wonder: what the heck is a "refspec" anyway? The answer is that it's a two—or sometimes three—part thing, with two branch1 names separated by a colon:

ours:theirs

for instance.2

"But wait," you might say, "there's no : in master, there's only one branch name!" Which is true, but git push needs two, so it makes up the other one: when you give one name, it duplicates the one you give it, so that master just means master:master.

This tells git push to push your current master and, on the other side, ask their git to update their master too.

If you want to push your current commit (HEAD) and have their git put that in as their master, you must3 write that out:

git push origin HEAD:master

It may help to realize that when you git push something, their side doesn't care (or even know) anything about any branches on your side: your git turns your branches into raw SHA-1 values, and sends those—the raw SHA-1s—to the remote. If your HEAD maps to commit-ID 1234567, for instance, git push origin HEAD:master has your git call theirs up and deliver commit 1234567, then send them a message: "now that I've given you commit 1234567, please make your master point to that commit-ID." Their end then says "OK" (push succeeded) or "no, I refuse" (push failed, e.g., not a fast-forward, or permission denied by a script like gitolite, or whatever). So any branch names you use that refer to your side—the left hand side of localname:remotename—are handled entirely on your end, and only the right-hand-side name is passed on to the remote git. That's why you can use HEAD:master.


1Actually, any valid reference can go here. Tags are references that start with refs/tags/, and git now has "notes" and such; all of these use references. But branches are the ones most people work with most of the time.

2The optional third part is a leading plus sign, for forcing updates, a la git push -f. Also, note that git fetch uses refspecs too, but in this case the names are reversed: theirs:ours, and you would normally fetch their master into your remotes/origin/master, for instance (with forced update, hence with a leading +).

3As usual with git, there's a configuration knob you can set to change the defaults. In this case there are multiple settings, but the main one to consider is push.default. See the git config documentation for details.

1
Ken Wayne VanderLinde On

You explicitly asked git to push to origin/master. In order to push to a new remote branch named example, you should write

git push -u origin example

The -u causes your local example branch to track the new remote example branch.