Jenkins Git插件分离的HEAD问题

89

我是Git和Jenkins的新手。我的问题是我无法让Jenkins Maven发布插件工作。

当我使用Jenkins构建Maven项目时,它可以正常工作,但当我尝试使用Maven发布插件进行发布时,我遇到了以下错误堆栈:

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

失败的命令和错误信息如下:

[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

我已经发现 Jenkins Git 插件创建了分离的 HEAD 引用 "(no branch)",导致了问题。但是我完全不知道为什么会创建这个引用,也不知道如何解决这个问题。

非常感谢任何帮助。


5
你的问题解决了吗?如果是的话,如果答案有帮助的话,可以接受该答案,或者提供你自己的解决方案以便其他人也能从中受益,谢谢! - Eugene Sajine
可能是Active Git branch is "(no branch)" on hudson CI的重复问题。 - Alberto
12个回答

101
当前(2.2.1)版本的Git插件已经移除了“Checkout/merge to local branch (optional)”字段。
它已经移至“Additional Behaviours”→“Check out to specific local branch”:

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

将该值设置为“master”即可获得一个检出的分支而非游离的HEAD。

5
如果你想建立多个分支,在GIT插件2.4.0(或之前的版本)中,你可以设置本地分支名称为$GIT_BRANCH,然后会获得一个与远程分支同名的分支。(刚刚发布了我的答案,并包含该信息)。 - Christian Semrau
2
只想强调将值设置为“**”或留空是更好的选择。本地分支名称将被计算。 origin/test -> test - Andrey Klochkov
@AndreyKlochkov,它确实可以做到你所说的,但问题在于它使用提交SHA作为起点,例如git checkout -b develop 1694bf...--这会阻止分支设置上游远程,这意味着您需要在事后手动设置一个shell脚本。 - Jon
对我来说,"*" 导致了一个错误,但将其留空则按预期工作。 - lewis
1
@lewis:我认为应该是两个星号,而不是一个。 - Matthias Braun

61

其他答案中的Jenkins配置都不适用于我,除非创建手动步骤。确实有效的方法是非常简单的:

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

25

更新(2015年11月):请注意,此解决方案是针对Git插件的特定版本(1.1.26)提供的。在后续版本中,该插件已更新以使配置更加容易。

对于Jenkins Git插件版本1.1.26,请尝试以下操作:

进入任务配置页面。向下滚动到Git部分,单击“存储库”下方的“高级...”按钮。然后设置:

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

然后点击另一个"高级..."按钮并进行如下设置:

Checkout/merge to local branch (optional): localbranchname

您可以随意为本地分支命名,但是Refspec中的目标必须与该可选字段中的本地分支名称匹配(在本例中为"localbranchname")。这将使HEAD附加到localbranchname上,如下所示:

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

Maven发布现在应该可以在Jenkins中通过。

顺便说一下,这对我来说使用Jenkins 1.492和Jenkins Git插件版本1.1.26有效。


5
本地分支(可选)设置是我唯一需要的。 - Zac Thompson
1
和我一样。这个(可选)设置产生了足够的差异。此外,我正在使用CloudBees,并在GitHub上注册了一个SSH密钥。向Maven发布插件提供用户名/密码会导致问题。最终,我成功地发布了没有用户名/密码的版本,让SSH接管。 - Jeff Fairley
4
顺便说一下,截至 Jenkins 1.547 版本(至少这是我正在使用的版本),第二个高级按钮已经消失了。您可以在“其他行为”下选择一个附加行为,以将代码检出到特定的本地分支。 - fbl
我在Jenkins 1.627中通过在“附加行为”下设置“检出到特定本地分支”字段为“master”来修复了这个问题。 - Derk
它部分地工作了,我的仓库现在在我想要的分支上,但当我尝试推送时,我会得到“fatal: The current branch master has no upstream branch”的错误。我已经在Jenkins Git配置中尝试了不同的参数,但没有运气,我只是不想像这样硬编码推送的分支名称 git push -u origin master - yorch

9
在Git中,当你检出一个分支(例如master、dev或任何其他本地分支)时,你的HEAD(.git文件夹中的文件)将包含对应分支的引用。因此,它是“附加”的。
当你执行某些操作(例如rebase、合并或检出特定提交时),即每次看到“no branch”时,你的HEAD没有对任何本地分支的引用,而是直接指向提交,即它具有实际的SHA-1。这意味着它是 “detached” —— 与任何分支分离。
并没有创建新的引用“no branch”。
命令git symbolic-ref HEAD检查HEAD内容是否为引用或SHA-1,并将其打印出来。
可以通过以下方式查看:
git checkout master
git symbolic-ref HEAD
git checkout HEAD~2 # going two commits back
git symbolic-ref HEAD
git checkout master # coming back

现在,Jenkins中的Git插件大多数情况下使用分离头状态下的代码。我不确定Maven发布插件是如何工作的,但我99%确信它需要您从特定分支发布。为了解决这个问题,我建议将以下内容指定为预构建步骤或shell命令:

git checkout master; git pull origin master

那将解决问题,希望如此;)

感谢您的帮助!我已经找到了检查主分支的方法。但是,Maven发布插件也使用Git插件来获取源代码,这意味着Maven发布插件只能使用参数调用发布目标。在这两个步骤之间没有调用预构建步骤的可能性。 - Michel Werren
好的,据我所知,发布目标是可以调整的。你知道它无法确定当前分支,因此你应该能够调整发布目标准备工作,以便能够在正确的分支上检出项目。我认为最好的方法是定义一个单一的分支,你总是从这个分支进行发布,比如主分支,并通过显式地检出主分支来改变你的“准备”目标,以适应插件。 - Eugene Sajine

8
我想建立几个分支,并按名称检查每个分支。我正在使用Git插件2.4.0。 Matthias Braun的答案可以让你获得一个命名分支,但它不是以远程分支命名的。 将本地分支设置为$GIT_BRANCH,而不是将其设置为master
我在此错误报告中找到了这个解决方案。

1
将本地分支设置为$GIT_BRANCH为我在远程创建了一个新的分支:origin/origin/master。留空参数似乎可以正常工作。 - apa64

6

当我尝试使用maven-release-plugin:2.5.3和maven-scm-provider-jgit:1.9.5从一个分支进行参数化版本构建时,我遇到了相同的问题。

我想要能够选择“参数化版本构建”的分支。然而这并不起作用,当我选择“检出/合并到本地分支(可选)”时可以工作,但是我最终得到了一个在远程上叫做“origin/origin/mybranch”的分支(重复的origin)。

因此:

  • 将“Git Parameter”添加到“This project is parameterized”中
    名称:branch
    ParameterType:Branch
    点击高级:
    Branch Filter:origin/(.*)
    (这就是诀窍!)

  • Git仓库:
    要构建的分支:refs/remotes/origin/${branch}

  • 其他行为:-> 检出到特定的本地分支
    分支名称:${branch}

玩得开心 :-)


这需要安装“Git参数”插件。 - MatPag

3

如果你正在使用来自SCM的管道脚本,以下是需要使用的语法来实现在另一个答案中所展示的效果:

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

例如,如果您的远程分支是develop,并且您想要检出一个名为develop的本地分支来跟踪它,那么这里是一个最简示例,展示了上下文中的本地分支扩展:

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

在这里,xxxyyy将分别被您自己的凭据ID和URL所替代。

您也可以使用图形化语法生成器自己生成流水线语法。请参见此答案


3
大部分以上的答案建议使用“检出到特定本地分支”作为解决方案。不幸的是,这并不是最佳选项,因为它将手动检出在管道配置中定义的本地分支。
很多时候,Jenkins被设置为使用Multibranch Pipeline模式工作,这意味着项目可以从不同的git分支构建。
在这种情况下,远程分支与本地分支不匹配。
解决方案
对于这些情况,最好和安全的解决方案是检出匹配的本地分支。例如,如果管道正在dev分支上工作,则会在本地检出dev分支。
为了实现这样的结果,在“分支源”部分添加一个额外的属性,命名为“检出到匹配的本地分支”。

2

将以下内容添加到用于发布准备的Maven命令行中:-DpushChanges=false -DlocalCheckout=true

这意味着Maven将使用Jenkins工作目录中的.git,而不是克隆远程或推送到远程。

我建议将完全限定的refs/remotes/origin/develop配置为您的Git“要构建的分支”。对我来说,这样更容易理解。

在这种情况下,Jenkins会自动将$GIT_BRANCH设置为origin/develop

然后,不要使用过于复杂(但可移植)的GitPublisher,只需添加一个后构建步骤“执行Shell”:

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

这会推送Maven更改的内容,例如pom.xml和标签。


1

我遇到了同样的问题。@Eugene的解决方案只起作用了一次。

第二次尝试时出现错误:“无法从仓库中删除HEAD”或类似的错误。

我找到了这个(source):

还有m2额外的步骤(预构建)

git checkout master || git checkout -b master

git reset --hard origin/master

现在我认为没问题了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接