How to reattach a detached HEAD in GIT

Remotec picture Remotec · Nov 7, 2017 · Viewed 14.1k times · Source

(I can see there are many questions about this but I haven't found one that solves my exact problem).

I'm running gitlab-ci and when the runner checks out my code it does so as a detached head. Here is what I get when running a git status command in the runners directory.

git status
# HEAD detached at 847fe59
nothing to commit, working directory clean

What I need to do for what I am working on is to re-attach this head back to my develop branch and then git pull in the full repo for use in a docker container. I guess gitlab ci only checks out the last commit to save cloning down the full repo which is understandable.

In my .gitlab-ci.yml file I've tried the following...

- git checkout origin/$CI_BUILD_REF_NAME
- git pull

Which gives the following output in the console...

    $ git checkout $CI_BUILD_REF_NAME
    Switched to a new branch 'develop'
    Branch develop set up to track remote branch develop from origin.
$ git pull
You are not currently on a branch. Please specify which
branch you want to merge with. See git-pull(1) for details.

Is there an easy way to reattach the head? Most of the solutions I've seen deal with the fact a change has been committed onto the detached head however this isn't the case for me. I just want to get my full develop branch in my docker container with all of my git history.

Or if there is a way to stop gitlab ci from checking out the detached head that would also be great.

Answer

torek picture torek · Nov 7, 2017

A detached HEAD is simply a HEAD containing the raw hash ID of a commit. As noted in the comments, it's generally pretty reasonable to use this for a build system, whether that's some sort of continuous integration or not: you might check out a specific commit by hash ID, or check out a tag name, but either way HEAD winds up containing the commit hash ID and is now guaranteed to be steady.

If you do want to have an "attached" (not-detached) HEAD, though, all you have to do in Git terms is to run git checkout <branch-name>. This writes the name of the branch into HEAD, and now HEAD is attached to that branch. This means that it's not HEAD at all, but rather the branch name, that determines which commit is current. Anything that updates the branch name, changes the current commit.

Note that this property only applies to branch names, i.e., with names that live in the refs/heads/ name-space. The name origin/branch is typically shorthand for refs/remotes/origin/branch, which is not a branch name; it's a remote-tracking name (sometimes called a remote-tracking branch, which is a poor set of words because that sure sounds like "branch", doesn't it?). Supplying any name to git checkout that can be resolved to a commit, but is not a branch name, results in a detached HEAD (if the checkout works at all, anyway).

If you want to have an attached HEAD, it must be attached to a branch name, i.e., a reference whose name starts with refs/heads/.