git 是否不可能在 Jenkinsfile 中签出不同的分支?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/45399894/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 05:04:57  来源:igfitidea点击:

Is it impossible to checkout a different branch in Jenkinsfile?

gitjenkinsbitbucketjenkins-pipeline

提问by Thomas K?sene

I have two branches on BitBucket: masterand develop. I've also got a BitBucket Team Folder job configured on my Jenkins server to build that repository. On the developbranch there's the following Jenkinsfile:

我在 BitBucket 上有两个分支:masterdevelop. 我还在我的 Jenkins 服务器上配置了一个 BitBucket 团队文件夹作业来构建该存储库。在develop分支上有以下 Jenkinsfile:

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

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

When Jenkins runs it, the build fails when it attempts to 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] }

I had expected the git branch -rcommand to print out both origin/masterand origin/develop, but for some reason it only prints the latter.

我原以为git branch -r命令会同时打印origin/masterorigin/develop,但由于某种原因,它只打印了后者。

I've read around and tried to come up with any ways to do this: For example, I tried installing the SSH Agent Plugin for Jenkins and changed the Jenkinsfile to:

我已经阅读并试图想出任何方法来做到这一点:例如,我尝试为 Jenkins 安装 SSH 代理插件并将 Jenkinsfile 更改为:

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

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

But it still doesn't appear to find origin/master. What's worse, the SSH agent seems to be killed before it attempts to 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] }

My eventual plan is to commit something to developand then merge it into master, but so far I have had very little luck. Has anybody got a possible solution or workaround?

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

PS: This only seems to be a problem in Jenkinsfile; I have a freestyle job that does something similar to what I want, and it works fine.

PS:这似乎只是 Jenkinsfile 中的一个问题;我有一份自由式工作,可以做一些与我想要的类似的事情,而且效果很好。

回答by Thomas K?sene

After some hours of trial and error, I came up with a possible solution. It builds partly on Matt's answer, but I had to alter it to make it work.

经过几个小时的反复试验,我想出了一个可能的解决方案。它部分建立在马特的回答上,但我必须对其进行更改才能使其正常工作。

Matt was correct in the essentials: checkout scmsimply wasn't flexible enough to allow me to do what I needed, so I had to use GitSCMto customize it. The major points of interest are:

马特在本质上是正确的:checkout scm只是不够灵活,无法让我做我需要的事情,所以我不得不使用GitSCM它来定制它。主要的兴趣点是:

  • Added extension LocalBranchto make sure I check out to an actual branch, and not just a detached HEAD.
  • Added extension WipeWorkspaceto delete everything in the workspace and force a complete clone. I don't think this was a part of the solution to my question, but it was still handy to have.
  • Specified the SSH credentials using the credentialsIdproperty since the repository is private.
  • 添加了扩展LocalBranch以确保我签出到一个实际的分支,而不仅仅是一个分离的HEAD.
  • 添加WipeWorkspace了删除工作区中所有内容并强制完整克隆的扩展。我不认为这是我的问题的解决方案的一部分,但它仍然很方便。
  • 使用credentialsId属性指定 SSH 凭据,因为存储库是私有的。

For whatever reason, when the checkoutstep is executed, it only checks out the branch, but does not set it to track the remote branch. Until I find a more elegant solution, I had to do this manually.

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

After all that was done, I could use regular sh "git checkout master"and even sh "git push", as long as I enclosed them in an sshagentstep.

完成所有这些之后,我可以使用常规sh "git checkout master"和偶数sh "git push",只要我将它们包含在一个sshagent步骤中。

I added a working example of the resulting Jenkinsfile below, but please keep in mind that it shouldn't be used for anything close to production as it's still very much in its infancy; hardcoded version numbers and no checks for which branch you're in, for example.

我在下面添加了生成的 Jenkinsfile 的一个工作示例,但请记住,它不应该用于任何接近生产的东西,因为它仍处于起步阶段;例如,硬编码的版本号并且不检查您所在的分支。

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: '[email protected]:NAVFREG/jenkinsfile-tests.git']],
            doGenerateSubmoduleConfigurations: false
        ])
    }

    stage('Release') {
        // Preparing Git
        sh "git branch -u origin/develop develop"
        sh "git config user.email \"[email protected]\""
        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"
        }
    }
}

回答by Matt Schuchard

You can use the intrinsic function in Jenkins Pipeline created for Git cloning and pulling. I would also suggest cloning the branches into separate directories.

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

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

回答by swoop81

I could not get the two answers above to work. I was triggering a Jenkins pipeline job by specifying a branch and was trying to checkout another branch (develop) in the job which was failing with:

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

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

I could see this in the failing job, which indicated that only the triggering branch was being fetched:

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

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

I got it to work by changing the remote fetch config and fetching all branches by doing the following after doing just the default checkout scmstep in the triggered job's Jenkinsfile:

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

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

This is thanks to this answer https://stackoverflow.com/a/39986737/1988883

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

This also avoids having to configure Jenkins for GitSCM script approvalswhich I had to do for trying out the two solutions above

这也避免了我必须为GitSCM 脚本批准配置 Jenkins来尝试上述两种解决方案

回答by D0m3

The problem is that Jenkins is defining the originwith only the branch that is discovered.

问题是 Jenkins 只定义了origin发现的分支。

@swoop81 answer is working but if you just want to checkout one branch, you could fetch only this one.

@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>

回答by Tom Chamberlain

You can use the gitcommand which is the less advanced version of the checkoutcommand

您可以使用git的命令,它是较不先进的版本checkout命令

stage('Repo Checkout') {
            steps {
                deleteDir()
                dir("repo-one-master") {
                    git url: "ssh://[email protected]/folder/project",
                        branch: 'master'
                }
                dir("repo-one-feature) {
                    git url: "ssh://[email protected]/folder/project",
                        branch: 'some-branch'
                }
            }
        }