Lets say I'm in a detached head state and I run the following command:
git push origin head:something/something/blah
git will output the following error:
So my question is: What is the correct keyword to use here instead of "head" to reference the current commit I'm on? I can copy paste the commit id, but that's obviously silly. I'm asking for a constant name I can type, like head, to represent the current commit I'm on.
CodePudding user response:
HEAD
is your current checkout. If you don't say the destination type explicitly (by supplying the refs/<type>/
prefix, e.g. refs/heads/
for branch tips), Git tries to figure out what you meant by copying the type from the source. But when you don't have a branch checked out and you supply HEAD
, there's no type to copy. It's just some random commit you're working on. That's what ... yeah, that error message you posted a picture of ... is talking about: you didn't say what kind of ref you're trying to create.
CodePudding user response:
As jthill notes, when HEAD
is detached, Git doesn't know whether:
git push origin HEAD:foo
is meant to create refs/heads/foo
(a branch named foo
) on origin
, or refs/tags/foo
(a tag named foo
) on origin
, or perhaps some other kind of ref (e.g., Gerrit's magic refs/for/foo
1).
Because you are in detached-HEAD mode in your current working tree, you must assist Git here. You can:
git push origin @:refs/heads/foo
to tell Git: Use HEAD
, in all upper case,2 to find the commit in my repository. Push that commit and any necessary parents to origin
, then ask origin
to create a branch named foo
.
It's probably easier, though, to just go ahead and create a local branch named foo
:
git switch -c foo
after which git push -u origin @
suffices. You might even wish to make an alias (shell alias or Git alias) or shell function out of this:
push-new-as foo
where push-new-as
expands to git switch -c $1 && git push -u origin @
for instance. (Add additional protections, such as making sure there's no origin/foo
first, if you like: that's probably actually a good idea. Have the alias-or-shell-function run git fetch origin
first.)
1Gerrit is written in JGit and doesn't implement Git quite the same as C Git. Pushing to a refs/for/
namespace name creates a Gerrit changeset, which Gerrit sneakily renames into yet another name. Your own (probably C-Git based) Git thinks Gerrit created refs/for/foo
successfully, as their JGit implemention returns a success indication at this point, but it really didn't. This little lie facilitates useful work and causes no actual problems, but it's definitely rather magic.
2See HEAD vs head vs detached HEAD for why the upper vs lower case distinction is important.