是否无法在Jenkinsfile中签出不同的分支?

时间:2017-07-30 12:36:50

标签: git jenkins bitbucket jenkins-pipeline

我在BitBucket上有两个分支:masterdevelop。我还在Jenkins服务器上配置了BitBucket Team Folder作业来构建该存储库。在develop分支上有以下Jenkins文件:

node {
    stage('Checkout') {
        checkout scm
    }

    stage('Try different branch') {
        sh "git branch -r"
        sh "git checkout master"
    }
}

当Jenkins运行它时,构建在尝试签出master时失败:

[Pipeline] stage
[Pipeline] { (Try different branch)
[Pipeline] sh
[e_jenkinsfile-tests_develop-4R65E2H6B73J3LB52BLACQOZLBJGN2QG22IPONX3CV46B764LAXA] Running shell script
+ git branch -r
  origin/develop
[Pipeline] sh
[e_jenkinsfile-tests_develop-4R65E2H6B73J3LB52BLACQOZLBJGN2QG22IPONX3CV46B764LAXA] Running shell script
+ git checkout master
error: pathspec 'master' did not match any file(s) known to git.
[Pipeline] }

我原本期望git branch -r命令可以打印origin/masterorigin/develop,但出于某种原因,它只打印后者。

我已经阅读并尝试了解任何方法:例如,我尝试为Jenkins安装SSH代理插件并将Jenkins文件更改为:

node {
    stage('Checkout') {
        checkout scm
    }

    stage('Try different branch') {
        sshagent(['Bitbucket']) {
            sh "git branch -r"
            sh "git checkout master"
        }
    }
}

但它似乎仍然没有找到origin/master。更糟糕的是,SSH代理似乎在尝试签出master之前被杀死了:

[Pipeline] { (Try different branch)
[Pipeline] sshagent
[ssh-agent] Using credentials ThomasKasene (Used to communicate with Bitbucket)
[ssh-agent] Looking for ssh-agent implementation...
[ssh-agent]   Exec ssh-agent (binary ssh-agent on a remote machine)
$ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-M6pIguCUpAV4/agent.11899
SSH_AGENT_PID=11902
$ ssh-add /var/jenkins_home/workspace/e_jenkinsfile-tests_develop-4R65E2H6B73J3LB52BLACQOZLBJGN2QG22IPONX3CV46B764LAXA@tmp/private_key_2394129657382526146.key
Identity added: /var/jenkins_home/workspace/e_jenkinsfile-tests_develop-4R65E2H6B73J3LB52BLACQOZLBJGN2QG22IPONX3CV46B764LAXA@tmp/private_key_2394129657382526146.key (/var/jenkins_home/workspace/e_jenkinsfile-tests_develop-4R65E2H6B73J3LB52BLACQOZLBJGN2QG22IPONX3CV46B764LAXA@tmp/private_key_2394129657382526146.key)
[ssh-agent] Started.
[Pipeline] {
[Pipeline] sh
[e_jenkinsfile-tests_develop-4R65E2H6B73J3LB52BLACQOZLBJGN2QG22IPONX3CV46B764LAXA] Running shell script
+ git branch -r
  origin/develop
[Pipeline] sh
$ ssh-agent -k
unset SSH_AUTH_SOCK;
unset SSH_AGENT_PID;
echo Agent pid 11902 killed;
[ssh-agent] Stopped.
[e_jenkinsfile-tests_develop-4R65E2H6B73J3LB52BLACQOZLBJGN2QG22IPONX3CV46B764LAXA] Running shell script
+ git checkout master
error: pathspec 'master' did not match any file(s) known to git.
[Pipeline] }

我最终的计划是将某些内容提交到develop,然后将其合并到master,但到目前为止,我的运气很少。有没有人有可能的解决方案或解决方法?

PS:这似乎只是Jenkinsfile中的一个问题;我有一个类似于我想要的自由式工作,并且工作正常。

5 个答案:

答案 0 :(得分:8)

经过几个小时的反复试验,我想出了一个可能的解决方案。它部分建立在马特的答案上,但我不得不改变它以使其发挥作用。

Matt在要点中是正确的:checkout scm根本不够灵活,无法让我做我需要的东西,所以我不得不使用GitSCM来自定义它。主要兴趣点是:

  • 添加了扩展程序LocalBranch,以确保我结帐到实际的分支机构,而不仅仅是分离的HEAD
  • 添加了扩展程序WipeWorkspace以删除工作区中的所有内容并强制完全克隆。我不认为这是我的问题的解决方案的一部分,但它仍然很方便。
  • 使用credentialsId属性指定SSH凭据,因为存储库是私有的。

无论出于何种原因,当执行checkout步骤时,它只会检出分支,但不会将其设置为跟踪远程分支。在找到更优雅的解决方案之前,我必须手动执行此操作。

完成所有操作后,我可以使用常规sh "git checkout master"甚至sh "git push",只要我将其括在sshagent步骤中。

我在下面添加了一个结果Jenkins文件的工作示例,但请记住,它不应该用于任何接近生产的东西,因为它仍处于初期阶段;例如,硬编码的版本号并没有检查您所在的分支。

node {
    mvnHome = tool 'Maven'
    mvn = "${mvnHome}/bin/mvn"

    stage('Checkout') {
        checkout([
            $class: 'GitSCM',
            branches: scm.branches,
            extensions: scm.extensions + [[$class: 'LocalBranch'], [$class: 'WipeWorkspace']],
            userRemoteConfigs: [[credentialsId: 'Bitbucket', url: 'git@bitbucket.org:NAVFREG/jenkinsfile-tests.git']],
            doGenerateSubmoduleConfigurations: false
        ])
    }

    stage('Release') {
        // Preparing Git
        sh "git branch -u origin/develop develop"
        sh "git config user.email \"jenkins@thomaskasene.com\""
        sh "git config user.name \"Jenkins\""

        // Making and committing new verison
        sh "${mvn} versions:set -DnewVersion=2.0.0 -DgenerateBackupPoms=false"
        sh "git commit -am \"Released version 2.0.0\""

        // Merging new version into master
        sh "git checkout master"
        sh "git merge develop"
        sh "git checkout develop"

        // Making and committing new snapshot version
        sh "${mvn} versions:set -DnewVersion=3.0.0-SNAPSHOT -DgenerateBackupPoms=false"
        sh "git commit -am \"Made new snapshot version 3.0.0-SNAPSHOT\""

        // Pushing everything to remote repository
        sshagent(['Bitbucket']) {
            sh "git push"
            sh "git checkout master"
            sh "git push"
        }
    }
}

答案 1 :(得分:5)

您可以使用为Git克隆和拉动创建的Jenkins管道中的内部函数。我还建议将分支克隆到单独的目录中。

checkout([$class: 'GitSCM',
  branches: [[name: '*/branch_name']],
  doGenerateSubmoduleConfigurations: false,
  extensions: [[$class: 'RelativeTargetDirectory',
    relativeTargetDir: 'different_directory']],
  submoduleCfg: [],
  userRemoteConfigs: [[url: 'git@github.domain:org/repo.git']]])

答案 2 :(得分:2)

我无法得到上面的两个答案。我通过指定一个分支触发了一个Jenkins管道作业,并试图检查失败的作业中的另一个分支(开发):

error: pathspec 'develop' did not match any file(s) known to git.

我可以在失败的工作中看到这一点,这表明只提取了触发分支:

git fetch --no-tags --progress https://<github URL> +refs/heads/branch-name:refs/remotes/origin/branch-name

我通过更改远程获取配置并通过在触发的作业的Jenkinsfile中执行默认checkout scm步骤后执行以下操作来获取所有分支来实现它:

sh """
    git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
    git fetch --all
"""

这要归功于这个答案https://stackoverflow.com/a/39986737/1988883

这也避免了必须为GitSCM script approvals配置Jenkins,我必须这样做才能尝试上面的两个解决方案

答案 3 :(得分:2)

您可以使用git命令,它是checkout命令的高级版本

stage('Repo Checkout') {
            steps {
                deleteDir()
                dir("repo-one-master") {
                    git url: "ssh://git@host.com/folder/project",
                        branch: 'master'
                }
                dir("repo-one-feature) {
                    git url: "ssh://git@host.com/folder/project",
                        branch: 'some-branch'
                }
            }
        }

答案 4 :(得分:1)

问题在于Jenkins仅使用发现的分支来定义origin

@ swoop81答案有效,但是如果您只想签出一个分支,则只能获取该分支。

git config --add remote.origin.fetch +refs/heads/<branch-name>:refs/remotes/origin/<branch-name>
git fetch --no-tags https://<github-url> +refs/heads/<branch-name>:refs/remotes/origin/<branch-name>