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
The syntax for
git pushis a bit obscure, but easy enough to explain for the particular case you are using:$ git push remote refspecThe
remoteyou 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
refspecyou 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:
for instance.2
"But wait," you might say, "there's no
:inmaster, there's only one branch name!" Which is true, butgit pushneeds two, so it makes up the other one: when you give one name, it duplicates the one you give it, so thatmasterjust meansmaster:master.This tells
git pushto push your currentmasterand, on the other side, ask their git to update theirmastertoo.If you want to push your current commit (
HEAD) and have their git put that in as theirmaster, you must3 write that out:It may help to realize that when you
git pushsomething, 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 yourHEADmaps to commit-ID 1234567, for instance,git push origin HEAD:masterhas your git call theirs up and deliver commit 1234567, then send them a message: "now that I've given you commit 1234567, please make yourmasterpoint 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 oflocalname: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 useHEAD: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 thatgit fetchuses refspecs too, but in this case the names are reversed:theirs:ours, and you would normally fetch theirmasterinto yourremotes/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 thegit configdocumentation for details.