Michel Werren
Michel Werren

Reputation: 1063

Jenkins Git plugin detached HEAD

I am new to Git and also to Jenkins. My problem is that I can't get the Jenkins Maven release plugin to work.

When I build a common Maven build with Jenkins, it works well, but when I try to perform a release with the Maven release plugin, I get the following stack trace:

org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-release-plugin:2.3.2:prepare (default-cli) on project parent: An error is occurred in the checkin process: Exception while executing SCM command.
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:217)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:320)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:156)
    at org.jvnet.hudson.maven3.launcher.Maven3Launcher.main(Maven3Launcher.java:79)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchStandard(Launcher.java:329)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:239)
    at org.jvnet.hudson.maven3.agent.Maven3Main.launch(Maven3Main.java:158)
    at hudson.maven.Maven3Builder.call(Maven3Builder.java:98)
    at hudson.maven.Maven3Builder.call(Maven3Builder.java:64)
    at hudson.remoting.UserRequest.perform(UserRequest.java:118)
    at hudson.remoting.UserRequest.perform(UserRequest.java:48)
    at hudson.remoting.Request$2.run(Request.java:326)
    at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:72)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
Caused by: org.apache.maven.plugin.MojoExecutionException: An error is occurred in the checkin process: Exception while executing SCM command.
    at org.apache.maven.plugins.release.PrepareReleaseMojo.prepareRelease(PrepareReleaseMojo.java:295)
    at org.apache.maven.plugins.release.PrepareReleaseMojo.execute(PrepareReleaseMojo.java:247)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:101)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209)
    ... 27 more
Caused by: org.apache.maven.shared.release.ReleaseExecutionException: An error is occurred in the checkin process: Exception while executing SCM command.
    at org.apache.maven.shared.release.phase.AbstractScmCommitPhase.checkin(AbstractScmCommitPhase.java:160)
    at org.apache.maven.shared.release.phase.AbstractScmCommitPhase.performCheckins(AbstractScmCommitPhase.java:145)
    at org.apache.maven.shared.release.phase.ScmCommitPreparationPhase.runLogic(ScmCommitPreparationPhase.java:76)
    at org.apache.maven.shared.release.phase.AbstractScmCommitPhase.execute(AbstractScmCommitPhase.java:78)
    at org.apache.maven.shared.release.DefaultReleaseManager.prepare(DefaultReleaseManager.java:234)
    at org.apache.maven.shared.release.DefaultReleaseManager.prepare(DefaultReleaseManager.java:169)
    at org.apache.maven.shared.release.DefaultReleaseManager.prepare(DefaultReleaseManager.java:146)
    at org.apache.maven.shared.release.DefaultReleaseManager.prepare(DefaultReleaseManager.java:107)
    at org.apache.maven.plugins.release.PrepareReleaseMojo.prepareRelease(PrepareReleaseMojo.java:291)
    ... 30 more
Caused by: org.apache.maven.scm.ScmException: Exception while executing SCM command.
    at org.apache.maven.scm.command.AbstractCommand.execute(AbstractCommand.java:63)
    at org.apache.maven.scm.provider.git.AbstractGitScmProvider.executeCommand(AbstractGitScmProvider.java:291)
    at org.apache.maven.scm.provider.git.AbstractGitScmProvider.checkin(AbstractGitScmProvider.java:217)
    at org.apache.maven.scm.provider.AbstractScmProvider.checkIn(AbstractScmProvider.java:410)
    at org.apache.maven.shared.release.phase.AbstractScmCommitPhase.checkin(AbstractScmCommitPhase.java:156)
    ... 38 more
Caused by: org.apache.maven.scm.ScmException: Detecting the current branch failed: fatal: ref HEAD is not a symbolic ref
    at org.apache.maven.scm.provider.git.gitexe.command.branch.GitBranchCommand.getCurrentBranch(GitBranchCommand.java:147)
    at org.apache.maven.scm.provider.git.gitexe.command.checkin.GitCheckInCommand.createPushCommandLine(GitCheckInCommand.java:192)
    at org.apache.maven.scm.provider.git.gitexe.command.checkin.GitCheckInCommand.executeCheckInCommand(GitCheckInCommand.java:132)
    at org.apache.maven.scm.command.checkin.AbstractCheckInCommand.executeCommand(AbstractCheckInCommand.java:54)
    at org.apache.maven.scm.command.AbstractCommand.execute(AbstractCommand.java:59)
    ... 42 more
channel stopped
Finished: FAILURE

The failing command and error message are:

[INFO] Executing: /bin/sh -c cd
/var/lib/jenkins/workspace/test_maven/parent && git symbolic-ref HEAD
[INFO]  Working directory:
/var/lib/jenkins/workspace/test_maven/parent  mojoFailed
org.apache.maven.plugins:maven-release-plugin:2.3.2(default-cli)
projectFailed ch.apkern.achilles:parent:1.0-SNAPSHOT  sessionEnded

I have figured out that the Jenkins Git plugin creates a detached HEAD ref "(no branch)" which causes the problem, I think. But I have absolutely no idea why this ref is created or how I can solve this problem.

I would be grateful for any help.

Upvotes: 90

Views: 71701

Answers (12)

Sebastian
Sebastian

Reputation: 6057

From https://docs.cloudbees.com/docs/cloudbees-ci-kb/latest/client-and-managed-masters/current-git-branch-is-head-detached-at:

When the Jenkins Git plugin clones a repo, it checks out a specific commit, rather than HEAD of the repo. This puts the repo in a "detached" state, so if you want to perform further git operations on the repo you need to attach to a branch with a checkout command in a shell step.

I solved it with a little "execute shell" step. (My branch parameter is called BRANCH).

BRANCH_NAME=${BRANCH##origin/}
git checkout ${BRANCH_NAME}
# git add and push stuff here
git push origin $BRANCH_NAME

Upvotes: 2

lukszar
lukszar

Reputation: 1422

Most of answers above suggest to use Check out to specific local branch as the solution for the mentioned problem. Unfortunately it's not the best option because it will checkout to local branch manually defined in configuration of Pipeline.

Many times Jenkins is set to work in Multibranch Pipeline mode, what means that project can be built from different git branches.

In such solution remote branch doesn't match to local one.

Solution

The best and secure solution for these cases is to check out to matching local branch. F.ex. if pipeline is working on dev branch it will checkout to dev branch locally.

To accomplish such result, add additional property in Branch Sources section, named: Check out to matching local branch

Upvotes: 5

Colm Bhandal
Colm Bhandal

Reputation: 3831

If you're working with a pipeline script from SCM, here is the piece of syntax needed to achieve what is shown graphically in another answer:

extensions: [[$class: 'LocalBranch', localBranch: 'BRANCH_NAME']]

So for example if your remote branch is develop and you want to checkout a local branch also called develop to track that, then here is a minimal example to show the local branch extension in context:

checkout([$class: 'GitSCM', branches: [[name: '*/develop']], extensions: [[$class: 'LocalBranch', localBranch: 'develop']], userRemoteConfigs: [[credentialsId: 'xxx', url: 'yyy']]])

Where xxx and yyy would be replace by your own credentials ID and URL, respectively.

You can also generate the pipeline syntax yourself using the graphical syntax generator. See this answer.

Upvotes: 5

Pawel
Pawel

Reputation: 828

I got the same problem. @Eugene solution worked only once.

There was an error on the second try: "can't delete HEAD from repository" or something like this.

I've found this (source):

And m2 extra steps (pre-build)

git checkout master || git checkout -b master

git reset --hard origin/master

And now I think it's ok.

Upvotes: 1

antoine
antoine

Reputation: 688

I had the same problem. I tried Constantine's solution, that worked perfectly but the tag and the commits were pushed on the "localbranchname" remote repository.

So I did the same but manually.

First, add a pre-steps shell script:

git branch -f localJenkins
git checkout localJenkins

Then a post-steps shell script:

git checkout master
git rebase localJenkins
git branch -D localJenkins
git push origin master
git push --tag

This works! This way, you don't have jenkins remote branch, commits and tag will be on the master (or other) branch.

Upvotes: 1

R.A
R.A

Reputation: 1871

I had the same issue when trying to do a parametrized release build from a branch with maven-release-plugin:2.5.3 and maven-scm-provider-jgit:1.9.5.

I wanted to be able to select the branch for the "parametrized release build". This did not work and when I chose "Checkout/merge to local branch (optional)" it worked but I ended up with a branch "origin/origin/mybranch" in remote (repeated origin).

So:

  • Add "Git Parameter" to "This project is parameterized"
    Name: branch
    ParameterType: Branch
    Click Advanced:
    Branch Filter:origin/(.*)
    (this was the trick!)

  • Git Repository:
    Branches to build: refs/remotes/origin/${branch}

  • Additional Behaviors: -> Check out to specific local branch
    Branch Name: ${branch}

Have fun :-)

Upvotes: 6

Christian Semrau
Christian Semrau

Reputation: 9013

I want to build several branches, and check out each branch under its name. I am using Git plugin 2.4.0.

The answer by Matthias Braun gets you a named branch, but it is not named after the remote branch.

Instead of setting the local branch to master, set the local branch to $GIT_BRANCH.

I found that solution in this bug report.

Upvotes: 8

Matthias Braun
Matthias Braun

Reputation: 34313

The Checkout/merge to local branch (optional) field is gone in the current (2.2.1) version of the Git plugin.

It has moved to Additional BehavioursCheck out to specific local branch:

Jenkins screenshot of setting option "Check out to specific local branch"

Setting that value to master got me a checked out branch instead of a detached head.

Upvotes: 103

Eugene Sajine
Eugene Sajine

Reputation: 8200

In Git, when you have a branch checked out, like master or dev or any other local branch, your HEAD (file in .git folder) will contain a reference to the corresponding branch. Therefore it is "attached".

When you perform some operations like rebase, merges or when you're checking out a particular commit, i.e. anytime you see "no branch", your HEAD doesn't have a reference to any local branch but points directly to the commit, i.e. it has the actual SHA-1 inside. That means it is detached - detached from any branch. There is no new reference "no branch" created.

The command git symbolic-ref HEAD checks if the HEAD content is a reference or a SHA-1 and prints it out.

You can see that by doing:

git checkout master
git symbolic-ref HEAD
git checkout HEAD~2 # going two commits back
git symbolic-ref HEAD
git checkout master # coming back

Now, most of the time the Git plugin in Jenkins works with the code in detached HEAD state. I'm not sure how the Maven release plugin works, but I'm 99% sure that it requires you to release from a specific branch. In order to fix that, I would recommend to specify something like the following as a prebuild step or shell command:

git checkout master; git pull origin master

That will solve the problem, I hope ;)

Upvotes: 9

Constantine
Constantine

Reputation: 424

UPDATE (November 2015): Please, note that this solution was given for a specific version of Git plugin (1.1.26). In later versions, the plugin was updated to make configuration easier.

For Jenkins Git plugin version 1.1.26 try this:

Go to Job Configuration. Scroll down to Git section and click "Advanced..." button under "Repositories". Then set:

Name: origin
Refspec: +refs/heads/branch-0.1:refs/remotes/origin/localbranchname

Then click another "Advanced..." button and set:

Checkout/merge to local branch (optional): localbranchname

You can name the local branch as you like, but the destination in Refspec must match the local branch name in that optional field (in this case "localbranchname"). This will attach HEAD to localbranchname like this:

HEAD -> refs/heads/localbranchname -> 7a698457751bdc043cfda631b81e3812c5361790

Maven Release should pass now in Jenkins.

By the way, this works for me with Jenkins 1.492 and Jenkins Git plugin version 1.1.26.

Upvotes: 25

Juraj Misur
Juraj Misur

Reputation: 1378

None of the other answer's Jenkins configurations worked for me without having to create manual steps. What indeed works is plain simple:

Repository URL: <repo>
Branches to build: master
Checkout/merge to local branch (optional): master

Upvotes: 61

kubanczyk
kubanczyk

Reputation: 5941

Add to maven command line for the release prepare: -DpushChanges=false -DlocalCheckout=true

This means maven would use what jenkins got inside working directory .git, and neither clone the remote or push to remote.

I recommend to configure fully qualified refs/remotes/origin/develop as your Git "Branch to build". This way it seems more understandable to me.

In such case your $GIT_BRANCH would get magically set by Jenkins to origin/develop

Then, instead of using overly complicated (but portable) GitPublisher, just add a post-build step "Execute Shell":

echo Remote branch is $GIT_BRANCH, replacing origin with refs/heads.
git push --follow-tags "$GIT_URL" "+HEAD:${GIT_BRANCH/#origin\//refs/heads/}"

This pushes whatever maven changed, like pom.xml and tags.

Upvotes: 2

Related Questions