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 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:
for instance.2
"But wait," you might say, "there's no
:
inmaster
, there's only one branch name!" Which is true, butgit push
needs two, so it makes up the other one: when you give one name, it duplicates the one you give it, so thatmaster
just meansmaster:master
.This tells
git push
to push your currentmaster
and, on the other side, ask their git to update theirmaster
too.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 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 yourHEAD
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 yourmaster
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 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 fetch
uses refspecs too, but in this case the names are reversed:theirs:ours
, and you would normally fetch theirmaster
into 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 config
documentation for details.