22

(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.

Remotec
  • 10,304
  • 25
  • 105
  • 147
  • 1
    This isn't 100% clear. Typically, CI systems check out a *specific* commit because there's no guarantee that the branch tip won't have moved on in the mean time (i.e. it ensures a deterministic code base). With that in mind, why do you need to checkout `develop` as part of your CI build? – Oliver Charlesworth Nov 07 '17 at 10:19
  • The main reason is so that I can run `gitversion` which automatically works out the `semver` etc based on the git repo. This doesn't work if I have a detached head. – Remotec Nov 07 '17 at 10:34
  • Hmm. Not that it's particularly helpful for me to say so, but that sounds like a bug/limitation in that tool - it ought to be able to compute a semver version from any commit. Unless of course the issue here is that your CI is only doing a shallow clone? (But that's different to it being a detached head.) – Oliver Charlesworth Nov 07 '17 at 10:57
  • It is indeed a limitation. I guess the upshot is that it's impossible to re-attach the head. – Remotec Nov 07 '17 at 11:14
  • 1
    @Remotec: you can use the `$CI_COMMIT_REF_NAME` environment variable to get the current branch. – siride Dec 29 '17 at 17:15

4 Answers4

22

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/.

torek
  • 448,244
  • 59
  • 642
  • 775
0

The other answers already explained a lot of background, and I realize the question is old, but since people may land here in search of a solution here you go:

job:
  script:
    - git switch $CI_COMMIT_REF_NAME #returning to branch from detached HEAD
    - <your CI script>
  variables:
    GIT_DEPTH: 0
    GIT_STRATEGY: clone

Note:

  1. You might as well use before_script: if you intend to use this as a template
  2. You might as well use git checkout over switch. checkout, however, can deal with branches and paths, so switch is a bit more targeted.
  3. GIT_STRATEGY: clone and GIT_DEPTH: 0 tell GitLab to create a full clone of the repo, including all branches and commits. Without that, the branch won't be known to git. GIT_DEPTH: 0 means that all commits will be cloned. As far as I know, this could safely be set to 100, for example.
Martin Schulze
  • 2,091
  • 2
  • 22
  • 27
-2

This worked for me

Command:

git checkout FETCH_HEAD

Output:

Previous HEAD position was 3cf5de5... Initial commit
HEAD is now at 600ea51... Sample Git Demo
Parag Jadhav
  • 1,853
  • 2
  • 24
  • 41
  • 1
    `FETCH_HEAD ` didn't work, I got this: `$ git checkout FETCH_HEAD error: pathspec 'FETCH_HEAD' did not match any file(s) known to git. ERROR: Job failed: exit code 1` – revelt Mar 09 '19 at 14:28
  • Enter `git fetch` first and then again try with `git checkout FETCH_HEAD` – Parag Jadhav Aug 21 '19 at 05:58
  • 1
    This command took me to another branch that was ahead of mine – Ivan Apr 08 '20 at 23:45
-2

i had about the same situation: you can always create a new branch and merge it with the branch you where detached from

Kampouse
  • 9
  • 4