Jenkins multibranch configuration for branches and tags.png
How to have Jenkins dispatch builds for tags pushed to your multibranch pipeline-enabled Git repository
A task so simple, and in principle possible, yet so hard to find documentation for.
I spent a good deal of time today bashing my head against my desk because my Jenkins multibranch pipelines were discovering tags I pushed to them, but not building them.
After much Web searching, I found the problem: Jenkins, by default, won't build anything that isn't a branch, even if the Jenkins pipeline successfully discovers other non-branch heads. Apparently, this is intended behavior! You have to manually build tags, if you want to build a tag at all.
In my humble opinion — after hours of frustration — sigh.
The solution
You can't change this behavior in the Jenkinsfile of your multibranch repository. You have to make the change in the configuration of the project itself.
First, install the basic branch build strategies plugin in your Jenkins setup. Restart Jenkins.
Then, you have to add two branch strategies to your multibranch pipeline:
- A regular branches build strategy.
- A tags build strategy.
Here's how you do this in three different ways:
Via the project configuration UI
This is how they look in the user interface for editing the multibranch pipeline configuration:

Editing project config.xml
If you're more the XML type for configuring Jenkins, add the boldened text from the following sample config.xml file to your multibranch pipeline configuration:
<?xml version='1.1' encoding='UTF-8'?>
<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject plugin="workflow-multibranch@821.vc3b_4ea_780798">
<actions/>
<description>Job digital-audio-bridge. Set up by generic build code.</description>
<displayName>digital-audio-bridge</displayName>
<properties/>
<folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api@2.1280.v0d4e5b_b_460ef">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</folderViews>
<healthMetrics>
<com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric plugin="cloudbees-folder@6.1079.vc0975c2de294">
<nonRecursive>false</nonRecursive>
</com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric>
</healthMetrics>
<icon class="jenkins.branch.MetadataActionFolderIcon" plugin="branch-api@2.1280.v0d4e5b_b_460ef">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</icon>
<orphanedItemStrategy class="com.cloudbees.hudson.plugins.folder.computed.DefaultOrphanedItemStrategy" plugin="cloudbees-folder@6.1079.vc0975c2de294">
<pruneDeadBranches>true</pruneDeadBranches>
<daysToKeep>-1</daysToKeep>
<numToKeep>-1</numToKeep>
<abortBuilds>false</abortBuilds>
</orphanedItemStrategy>
<triggers/>
<disabled>false</disabled>
<sources class="jenkins.branch.MultiBranchProject$BranchSourceList" plugin="branch-api@2.1280.v0d4e5b_b_460ef">
<data>
<jenkins.branch.BranchSource>
<source class="jenkins.plugins.git.GitSCMSource" plugin="git@5.10.0">
<id>digital-audio-bridge</id>
<remote>file:///srv/git/digital-audio-bridge.git</remote>
<credentialsId></credentialsId>
<traits>
<jenkins.plugins.git.traits.BranchDiscoveryTrait/>
<jenkins.plugins.git.traits.TagDiscoveryTrait/>
</traits>
</source>
<strategy class="jenkins.branch.DefaultBranchPropertyStrategy">
<properties class="empty-list"/>
</strategy>
<buildStrategies>
<jenkins.branch.buildstrategies.basic.BranchBuildStrategyImpl plugin="basic-branch-build-strategies@317.v85b_331d6cc42"/>
<jenkins.branch.buildstrategies.basic.TagBuildStrategyImpl plugin="basic-branch-build-strategies@317.v85b_331d6cc42">
<atLeastMillis>-1</atLeastMillis>
<atMostMillis>604800000</atMostMillis>
</jenkins.branch.buildstrategies.basic.TagBuildStrategyImpl>
</buildStrategies>
</jenkins.branch.BranchSource>
</data>
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</sources>
<factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
<scriptPath>Jenkinsfile</scriptPath>
</factory>
</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>
Using JobDSL
You may be using a job DSL to define your multibranch pipelines. Here is how my job DSL does it (again, the relevant code is boldened):
def defineJobViaDSL(job) {
jobDsl(
scriptText: """
multibranchPipelineJob("${job}") {
description "Job ${job}. Set up by generic build code."
displayName "${job}"
branchSources {
git {
id = "${job}"
remote("file:///srv/git/${job}.git")
}
}
triggers {
cron("H H * * *")
}
configure { x ->
x / orphanedItemStrategy(class: 'com.cloudbees.hudson.plugins.folder.computed.DefaultOrphanedItemStrategy') {
pruneDeadBranches('true')
daysToKeep('-1')
numToKeep('-1')
}
def traits = x / sources / data / 'jenkins.branch.BranchSource' / source / traits
traits << 'jenkins.plugins.git.traits.BranchDiscoveryTrait' {}
traits << 'jenkins.plugins.git.traits.TagDiscoveryTrait' {}
def buildStrategies = x / sources / data / 'jenkins.branch.BranchSource' / buildStrategies
buildStrategies << 'jenkins.branch.buildstrategies.basic.BranchBuildStrategyImpl' {}
buildStrategies << 'jenkins.branch.buildstrategies.basic.TagBuildStrategyImpl' {
atLeastMillis(-1)
atMostMillis(604000000)
}
}
if (!jenkins.model.Jenkins.instance.getItemByFullName("${job}")) {
queue("${job}")
}
}
""",
sandbox: true
)
}
Presto. From now on, every time you push a tag to your multibranch pipeline — whether according to your SCM polling settings, or because you called the /job/<JOB>/build REST API endpoint — discovered tags will be built.