Reputation: 1968
Recently I had a scenario where I was in a detached HEAD state. I wanted to push this to a fork on github in order to share some work-in-progress code with a teammate. I had no need for a local branch name for this particular commit.
Clearly, this would not work:
git push sandy-github HEAD
That makes sense, as I wasn't specifying a name for the remote branch.
But I don't understand why this did not work:
git push sandy-github HEAD:mynewbranch
This resulted in the following error:
error: unable to push to unqualified destination: mynewbranch The destination refspec neither matches an existing ref on the remote nor begins with refs/, and we are unable to guess a prefix based on the source ref. error: failed to push some refs to '[email protected]:sandyarmstrong/myreponame.git'
I ended up having to do:
git push sandy-github HEAD:refs/heads/mynewbranch
This worked. From the docs:
git push origin master:refs/heads/experimental
Create the branch experimental in the origin repository by copying the current master branch. This form is only needed to create a new branch or tag in the remote repository when the local name and the remote name are different; otherwise, the ref name on its own will work.
I just don't understand why this was necessary. I'm guessing there's something important about git I'm misunderstanding here. Why is this trickier syntax necessary just because the names don't match? Why isn't the HEAD:mynewbranch
syntax sufficient to let git know that it should generate a new branch on the remote named "mynewbranch"?
Upvotes: 9
Views: 1709
Reputation: 42547
The refspec
part of the git push
documentation has this (emphasis mine):
The
<dst>
tells which ref on the remote side is updated with this push. Arbitrary expressions cannot be used here, an actual ref must be named. If:<dst>
is omitted, the same ref as<src>
will be updated.
In the normal state, git can determine that you meant to push to a certain branch (or tag) based on branch tracking and/or values of push.default
in config.
In the detached HEAD state, git cannot guess whether you want to create a new branch or a new tag (both could be reasonable here).
It's possible to imply that the branch be created by creating the local branch first:
git checkout -b mynewbranch
git push -u sandy-github mynewbranch
If you don't want to checkout the branch you're pushing, you can use the refs/heads/
prefix as you mentioned in your question:
git push sandy-github HEAD:refs/heads/mynewbranch
Upvotes: 8
Reputation: 490078
Git has a fair amount of "magic" or "DWIM"* in many commands. "Push" has this: if you push local branch b
to the remote and the remote has a b
, it uses the magic/DWIM part to reconcile the local ref (whose "real" name is refs/heads/b
) with the remote one (whose name, on the remote, is also refs/heads/b
). But you can also push refs/tags/t
, or now that notes exist, refs/notes/commits
.
It already also has magic/DWIM to realize that a local ref y
that resolves to the local full-name refs/x/y
should create the same refs/x/y
on the remote when you use y:y
, even if y
does not exist on the remote. It's just that if the local full-name does not resolve to something like this, that this fails. It can even resolve HEAD when it is the symbolic name of a branch, but when HEAD is "detached", there is no symbolic name.
It could assume that git push HEAD:foo
"means" to create refs/heads/foo
. That's probably the most likely, hence what you meant. But, it does not (yet?).
*DWIM: "Do What I Mean" (as opposed to what I say).
Upvotes: 1
Reputation: 2962
This actually works fine for me. Are you on an older version of git or something?
For reference, I ran the following:
MacBook:AndroidAsync[master*]$ git commit -a -m gitignore
[master 69851e1] gitignore
1 file changed, 1 insertion(+)
MacBook:AndroidAsync[master]$ git push origin HEAD:master
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 343 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
To ssh://[email protected]/koush/AndroidAsync
04b2f79..69851e1 HEAD -> master
Version:
MacBook:AndroidAsync[master]$ git --version
git version 1.8.2.1 (Apple Git-45)
Also confirmed to work from detached HEAD:
MacBook:AndroidAsync[(no branch)]$ git push origin HEAD:master
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 332 bytes, done.
Total 3 (delta 1), reused 1 (delta 0)
To ssh://[email protected]/koush/AndroidAsync
69851e1..ae2d1be HEAD -> master
Upvotes: -1