Can't check out another branch in Jenkinsfile?
I have two branches on BitBucket: master
and develop
. I also have a TeamBacket Team Folder job configured on my Jenkins server to create this repository. The branch develop
contains the following Jenkins file:
node {
stage('Checkout') {
checkout scm
}
stage('Try different branch') {
sh "git branch -r"
sh "git checkout master"
}
}
When Jenkins starts it, the build fails when trying to check 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 expected the command git branch -r
to print both origin/master
and origin/develop
but for some reason it only prints the latter.
I read and tried to think of any ways to do this: for example, I tried installing the SSH Agent Plugin for Jenkins and modified the Jenkins file to:
node {
stage('Checkout') {
checkout scm
}
stage('Try different branch') {
sshagent(['Bitbucket']) {
sh "git branch -r"
sh "git checkout master"
}
}
}
But he still doesn't find origin/master
. To make matters worse, the SSH agent seems to be killed before it tries to check 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 possible plan is to convey something develop
and then combine it into master
, but so far I've had very little luck. Anyone got a possible solution or workaround?
PS: This only seems to be a problem in Jenkinsfile; I have a freestyle that does something similar to what I want and it works great.
source to share
After hours of trial and error, I came up with a possible solution. It is partially based on Matt's answer, but I had to change it to make it work.
Matt was mostly right: he checkout scm
just wasn't flexible enough to let me do what I needed, so I had to use GitSCM
it to customize it. Major attractions:
- Added an extension
LocalBranch
to make sure I check out the actual branch and not just the detached oneHEAD
. - Added an extension
WipeWorkspace
to remove everything in the workspace and force the full clone to quit. I don't think this was part of the solution to my question, but it was still handy to have. - Specifies SSH credentials using the property
credentialsId
because the repository is private.
For whatever reason, when a step is done checkout
, it only checks out the branch, but doesn't set it to track the remote branch. Until I found a more elegant solution, I had to do it manually.
After everything I've done, I could use regular ones sh "git checkout master"
and even sh "git push"
if I attached them to a step sshagent
.
I've added a working example of a Jenkins resulting file below, but please keep in mind that it shouldn't be used for anything close to production as it's still very rudimentary; hardcoded version numbers and no checks for which branch you are on, eg.
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"
}
}
}
source to share
You can use the built-in function in Jenkins Pipeline built to clone and pull Git. I would also suggest cloning branches into separate directories.
checkout([$class: 'GitSCM',
branches: [[name: '*/branch_name']],
doGenerateSubmoduleConfigurations: false,
extensions: [[$class: 'RelativeTargetDirectory',
relativeTargetDir: 'different_directory']],
submoduleCfg: [],
userRemoteConfigs: [[url: 'git@github.domain:org/repo.git']]])
source to share
I couldn't get the two answers above to work. I started working with Jenkins pipeline by specifying a branch and trying to checkout another branch (develop) on a job that didn't fire:
error: pathspec 'develop' did not match any file(s) known to git.
I could see this in the failed task, which indicated that only the activating branch was being checked out:
git fetch --no-tags --progress https://<github URL> +refs/heads/branch-name:refs/remotes/origin/branch-name
I got it to work by modifying the remote fetch configuration and fetching all branches by doing the following, only checkout scm
following the default step in the running Jenkinsfile job:
sh """
git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
git fetch --all
"""
This is thanks to this answer fooobar.com/questions/188886 / ...
This also avoids having to configure Jenkins for a GitSCM approval script , which I had to do to try out the two solutions above
source to share
The problem is that Jenkins origin
only defines with the discovered branch.
@ swoop81's answer, but if you just want to checkout one branch, you can only get this one.
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>
source to share