Search code examples
gitgit-branchgit-pushgit-detached-head

Can I push a commit made in detached HEAD state


Using git I would like to go into detached HEAD state and create a new commit. I'd then like to create a tag and push both the 'detached commit' and the tag to the remote repo. Is this possible?

If I create the detached commit in my local repo and create a tag then I can checkout the tag to get back to that state. I'd like to share that with the remote repo so that other uses can clone the repo and checkout the tag and get to that same state.

The reason I want to do this is because the build process needs to capture the build # in a file but I don't want to commit that to the branch where development is ongoing. I want the commit to be separate, but also want to capture the commit and tag it so that anyone can checkout the tag and the files that are included in the build. Is it recommended to push the commit to different branch, say "build"?


Solution

  • Yes, this—by "this" I mean the main question, "can you push a tagged but not branch-contained commit?"—is perfectly fine. Note that git push works by calling up some other Git (e.g., ssh://... or https://... call up the other Git over the Internet-phone), delivering some commit(s) if necessary, and then asking that other Git: "please set a reference name to point to some specific commit(s)".

    Since you have a tag, you can ask that other Git to please set the same tag. Assuming the remote is named origin (as it typically is):

    git push origin <tag>
    

    You can spell out the full name, refs/tags/tag, if needed. If tag names are easily distinguished from branch names (e.g., tags are v2.x and branches never start with v) it won't ever be needed (but it might still be wise in general).

    If you did not have a tag, you could still do it, but you would have to provide the other Git a name. To do that, you would do something like:

    git push origin HEAD:refs/heads/newbranch
    

    or:

    git push origin HEAD:refs/tags/newtag
    

    The tricky bit here is that during the push, you have no idea whether they have a branch newbranch or tag newtag already. If you've set a tag yourself, and have also been fetching from them all along, you probably have a good idea—not a guarantee, of course—that they do not have that tag yet either.

    Note that if they do have that name, and you politely request that they change their name to point to some other commit, they may refuse. This is when you see rejected errors from push. You can command them (using git push --force or the + prefix syntax on a refspec), but that's usually not the right way to go, plus they can still refuse (that part is up to whoever controls the other Git).