{"id":884,"date":"2024-08-21T00:26:00","date_gmt":"2024-08-21T00:26:00","guid":{"rendered":"https:\/\/blog.ngocha.biz\/?p=884"},"modified":"2024-08-21T00:26:00","modified_gmt":"2024-08-21T00:26:00","slug":"jenkins-multibranch-pipeline-tutorial","status":"publish","type":"post","link":"https:\/\/blog.ngocha.biz\/?p=884","title":{"rendered":"Jenkins Multibranch Pipeline Tutorial For Beginners"},"content":{"rendered":"<p>If you are looking for a well-automated <strong>Pull Request based or branch-based<\/strong> Jenkins <strong>Continuous Integration<\/strong> &amp; <strong>Delivery<\/strong> (CI\/CD) pipeline, this guide will help you get the overall picture of how to achieve it using the Jenkins multibranch pipeline.<\/p>\n<p>Jenkins&#8217;s multi-branch pipeline is one of the best ways to design CI\/CD workflows as it is entirely a git-based (source control) pipeline as code. This guide will talk about all the key concepts involved in a Jenkins multi-branch pipeline setup.<\/p>\n<h2 id=\"jenkins-multibranch-pipeline-fundamentals\">Jenkins Multibranch Pipeline Fundamentals<\/h2>\n<p>Let\u2019s start with the multi-branch pipeline basics. Specifically, in this section, I will cover the concept of a multi-branch pipeline and why it is essential to use it for all Jenkins CI\/CD pipelines.<\/p>\n<p>I\u2019ll also show you how a multi-branch pipeline works with a detailed workflow diagram.<\/p>\n<h2 id=\"what-is-a-multi-branch-pipeline\">What is a Multi-branch Pipeline?<\/h2>\n<p>A multi-branch pipeline is a concept of automatically creating Jenkins pipelines based on Git branches.<\/p>\n<p>It can automatically discover new branches in the source control (Github) and <strong>automatically create a pipeline for that branch<\/strong>. When the pipeline build starts, Jenkins uses the <strong><code>Jenkinsfile<\/code><\/strong> in that branch for build.<\/p>\n<p>SCM (Source Control) can be Github, Bitbucket, or a Gitlab repo.<\/p>\n<figure class=\"kg-card kg-image-card kg-card-hascaption\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/multi-branch-workflow-git-1.gif\" class=\"kg-image\" alt=\"What is a Multi-branch Pipeline?\" loading=\"lazy\" width=\"756\" height=\"511\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/multi-branch-workflow-git-1.gif 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/multi-branch-workflow-git-1.gif 756w\" sizes=\"auto, (min-width: 720px) 720px\"><figcaption><span style=\"white-space: pre-wrap;\">Click to view in HD<\/span><\/figcaption><\/figure>\n<p>You can choose to <strong>exclude selected branches<\/strong> if you don&#8217;t want them to be in the automated pipeline with Java regular expressions.<\/p>\n<p>Multi-branch pipeline supports<strong> PR based branch discovery<\/strong>. Meaning, branches get discovered automatically in the pipeline if someone raises a PR (pull request) from a branch or a forked repository. So if you are looking for a Pull Request based Jenkins build workflow, this is a great option.<\/p>\n<p>Also, you can add conditional logic to the <strong><code>Jenkinsfile<\/code><\/strong> to build jobs based on the branch requirement.<\/p>\n<p>For example, if you want the&nbsp;develop&nbsp;branch to run only unit testing, sonar analysis and artifact build, you can have a condition to skip the deployment stage with a&nbsp;<strong><code>when<\/code><\/strong>&nbsp;a condition, as shown below.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/develop-1.png\" class=\"kg-image\" alt=\"multibranch pipeline condition\" loading=\"lazy\" width=\"587\" height=\"501\"><\/figure>\n<p>So whenever the code is merged <strong><code>develop<\/code><\/strong> branch, the pipeline will run the unit testing and sonar analysis stages skipping the deployment stage.<\/p>\n<p>Also, multi-branch pipelines are not limited to the continuous delivery of applications. You can use it to manage your infrastructure code as well.<\/p>\n<p>One such example is having a continuous delivery pipeline for <a href=\"https:\/\/devopscube.com\/build-docker-image\/\">Docker image builds <\/a>, terraform deployment pipeline, VM image patching, building, and upgrade process.<\/p>\n<h2 id=\"how-does-a-multi-branch-pipeline-work\">How Does a Multi-Branch Pipeline work?<\/h2>\n<p>I will walk you through a <strong>basic git-flow based build and deployment<\/strong> workflow to understand multi-branch pipeline in a better way. The branching strategy provided in this example is for explanation purposes only.<\/p>\n<p>Let&#8217;s say I want a Jenkins pipeline to build and deploy an application with the following conditions.<\/p>\n<ol>\n<li>The application repo would have two branches (main and develop)<\/li>\n<li>Development starts with the developer forking the application repository and creating a branch in the forked repository. The developer commits code to the feature branch. Once the code is locally tested and ready for integration, they will <strong>raise a PR to the develop branch<\/strong> of the main repository from the forked repo.<\/li>\n<li>Whenever a developer raises a PR from the feature branch of the forked repository to the develop branch, a Jenkins pipeline should trigger to <strong>merge the source and target branches<\/strong>, followed by running unit tests and static code analysis. Lets call it as PR build.<\/li>\n<li>After the code passes the tests in the PR build, the developer or reviewer <strong>merges the PR<\/strong> into the develop branch.<\/li>\n<li>Once the code is merged it to develop branch, it should trigger a pipeline that will run the relevant tests and deploy the code in relevant envirnments (Eg, dev, qa, etc)<\/li>\n<li>When the code is ready for release, developers raise a PR from the develop branch to the master branch. This should <strong>trigger a PR build pipeline<\/strong> that will merge the source and target branches, run unit tests, perform code analysis, build artifacts (docker image, jar files etc), conduct vulnerability tests, etc.<\/li>\n<li>If the tests pass, the PR will be reviewed and merged into the main branch.<\/li>\n<li>When the merge happens, Jenkins should trigger a build that will compile the code, create a release artifact, and deploy it to the staging and pre-production environments.<\/li>\n<\/ol>\n<p>From the above conditions, you can see that <strong>there is no manual trigger of Jenkins jobs<\/strong>, and whenever there is a pull request for a branch, the pipeline needs to be triggered automatically and run the required steps for that branch.<\/p>\n<p>This workflow builds a <strong>great feedback loop for engineers<\/strong> and avoids dependence on the DevOps team to build and deploy in non-prod environments.<\/p>\n<p>Developer can check the build status on Github and take decisions on what to do next.<\/p>\n<p>This workflow can be achieved easily through a Jenkins multi-branch pipeline.<\/p>\n<p>The following image shows how a multi-branch pipeline workflow would look like for the above example build process.<\/p>\n<figure class=\"kg-card kg-image-card kg-card-hascaption\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/multi-branch-pr-workflow-1.gif\" class=\"kg-image\" alt=\"multibranch pipeline Pull request workflow animation\" loading=\"lazy\" width=\"741\" height=\"617\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/multi-branch-pr-workflow-1.gif 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/multi-branch-pr-workflow-1.gif 741w\" sizes=\"auto, (min-width: 720px) 720px\"><figcaption><span style=\"white-space: pre-wrap;\">Click to view in HD<\/span><\/figcaption><\/figure>\n<p>Here is how the multi-branch pipeline works.<\/p>\n<ol>\n<li>When a developer creates a PR from a feature branch from forked repo to develop a branch, Github sends a webhook with the  PR information to Jenkins.<\/li>\n<li>Jenkins receives the PR and finds the relevant multibranch pipeline, and creates a PR build pipeline automatically. It then runs the jobs with the steps mentioned in the <strong><code>Jenkinsfile<\/code><\/strong>. During checkout, the <strong>source and target branches<\/strong> in the PR gets merged. The PR merge will be blocked on Github until a build status from Jenkins is returned (It Github ruleset is configured).<\/li>\n<li>Once the build finishes, Jenkins will update the status to Github PR. Now you will be able to merge the code. If you want to check the Jenkins build logs, you can find the Jenkins build status and log link in the PR status (If Github App forJenkins is configured).<\/li>\n<\/ol>\n<h2 id=\"multibranch-pipleline-jenkinsfile\">Multibranch Pipleline Jenkinsfile<\/h2>\n<p>Before jumping into implementation, let&#8217;s look at multibranch pipeline Jenkins example Jenkinsfile that can be used in the pipeline.<\/p>\n<p>For the multibranch pipeline to work, you need to have the Jenkinsfile in the SCM repo.<\/p>\n<p>If you are learning\/testing, you can use the multibranch pipeline Jenkinsfile given below. It has a checkout stage and other dummy stages, which echoes the message.<\/p>\n<p>Also, you can clone and use&nbsp;<a href=\"https:\/\/github.com\/devopscube\/multibranch-pipeline-demo?ref=devopscube.com\" rel=\"noopener noreferrer\">this Github repo<\/a>&nbsp;which has this Jenkinsfile.<\/p>\n<div class=\"kg-card kg-callout-card kg-callout-card-grey\">\n<div class=\"kg-callout-text\"><b><strong style=\"white-space: pre-wrap;\">Note<\/strong><\/b>: Replace the agent label <b><code spellcheck=\"false\" style=\"white-space: pre-wrap;\"><strong>agent-01<\/strong><\/code><\/b> with your Jenkins agent name.<\/div>\n<\/div>\n<pre><code>pipeline {\n\n    agent {\n        node {\n            label 'agent-01'\n        }\n    }\n\n    options {\n        buildDiscarder logRotator( \n            daysToKeepStr: '16', \n            numToKeepStr: '10'\n        )\n    }\n\n    stages {\n        \n        stage('Cleanup Workspace') {\n            steps {\n                cleanWs()\n                sh \"\"\"\n                echo \"Cleaned Up Workspace For Project\"\n                \"\"\"\n            }\n        }\n\n        stage('Code Checkout') {\n            steps {\n                checkout([\n                    $class: 'GitSCM', \n                    branches: [[name: '*\/main']], \n                    userRemoteConfigs: [[url: 'https:\/\/github.com\/spring-projects\/spring-petclinic.git']]\n                ])\n            }\n        }\n\n        stage('Unit Testing') {\n            steps {\n                sh \"\"\"\n                echo \"Running Unit Tests\"\n                \"\"\"\n            }\n        }\n\n        stage('Code Analysis') {\n            steps {\n                sh \"\"\"\n                echo \"Running Code Analysis\"\n                \"\"\"\n            }\n        }\n\n        stage('Deploy To Dev &amp; QA') {\n            when {\n                branch 'develop'\n            }\n            steps {\n                sh \"\"\"\n                echo \"Building Artifact for Dev Environment\"\n                \"\"\"\n                sh \"\"\"\n                echo \"Deploying to Dev Environment\"\n                \"\"\"\n                sh \"\"\"\n                echo \"Deploying to QA Environment\"\n                \"\"\"\n            }\n        }\n\n        stage('Deploy To Staging and Pre-Prod Code') {\n            when {\n                branch 'main'\n            }\n            steps {\n                sh \"\"\"\n                echo \"Building Artifact for Staging and Pre-Prod Environments\"\n                \"\"\"\n                sh \"\"\"\n                echo \"Deploying to Staging Environment\"\n                \"\"\"\n                sh \"\"\"\n                echo \"Deploying to Pre-Prod Environment\"\n                \"\"\"\n            }\n        }\n\n    }   \n}\n<\/code><\/pre>\n<h2 id=\"setup-jenkins-multi-branch-pipeline\">Setup Jenkins Multi-branch  Pipeline<\/h2>\n<p>Now, I will walk you through the step by step process of setting up a multi-branch pipeline on Jenkins.<\/p>\n<p>This setup will be based on Github and latest Jenkins version.<\/p>\n<p>If you are learning, you can use the following repository as a reference for the pipeline.<\/p>\n<pre><code>https:\/\/github.com\/techiescamp\/jenkins-pipelines<\/code><\/pre>\n<div class=\"kg-card kg-callout-card kg-callout-card-grey\">\n<div class=\"kg-callout-text\"><b><strong style=\"white-space: pre-wrap;\">Important Note:<\/strong><\/b> You need to create your own repository to test the multibranch pipeline.<\/div>\n<\/div>\n<h2 id=\"create-multibranch-pipeline-step-by-step-guide\">Create Multibranch Pipeline <br \/>(Step by Step Guide)<\/h2>\n<p><strong>Step 1: <\/strong>From the Jenkins home page create a \u201cnew item\u201d.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/jenkins-new-item-2.png\" class=\"kg-image\" alt=\"Jenkins new item- multibranch\" loading=\"lazy\" title=\"jenkins-new-item\" width=\"662\" height=\"332\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/jenkins-new-item-2.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/jenkins-new-item-2.png 662w\"><\/figure>\n<p><strong>Step 2: <\/strong>Select the \u201cMultibranch pipeline\u201d from the option and click ok.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-229.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"935\" height=\"1002\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-229.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-229.png 935w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p><strong>Step 3: <\/strong>Click \u201cAdd a Source\u201d and select Github.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/jenkins-select-github-min-2.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" title=\"jenkins select Github-min\" width=\"748\" height=\"562\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/jenkins-select-github-min-2.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/jenkins-select-github-min-2.png 748w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p><strong>Step 4: <\/strong>Under the credentials field, select Jenkins, and create a credential with your Github username and password.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-1-25.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"602\" height=\"335\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-1-25.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-1-25.png 602w\"><\/figure>\n<p><strong>Step 5: <\/strong>Select the created credentials and provide your Github repo to validate the credentials as shown below.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/validate-credentials-min-2.png\" class=\"kg-image\" alt=\"validate multibranch pipeline credentials\" loading=\"lazy\" title=\"validate credentials-min\" width=\"882\" height=\"266\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/validate-credentials-min-2.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/validate-credentials-min-2.png 882w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p><strong>Step 6:<\/strong> Under &#8220;<strong>Behaviours<\/strong>&#8221; select the required option matches your requirement. You can either choose to discover all the branches in the repo or only branches with a Pull Request.<\/p>\n<p>The pipeline can discover branches with a PR from a forked repo as well. Choosing these options depends on your required workflow.<\/p>\n<p>The options shown below is for the PR based workflow I explained earlier in the guide.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-31-12.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"624\" height=\"667\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-31-12.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-31-12.png 624w\"><\/figure>\n<p>There are additional&nbsp;behavior&nbsp;you can choose from the \u201cadd\u201d button.&nbsp;<\/p>\n<p>For example, If you choose not to discover all the branches from the repo, you can opt for the regular expression or wildcard method to discover branches from the repo as shown below.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/filter-options-min-2.png\" class=\"kg-image\" alt=\"Multibranch pipeline regular expression\" loading=\"lazy\" title=\"filter-options-min\" width=\"588\" height=\"609\"><\/figure>\n<p>Here is a regex and wildcard example.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/filter-examples-2.png\" class=\"kg-image\" alt=\"Multibranch Pipeline filter examples\" loading=\"lazy\" title=\"filter examples\" width=\"665\" height=\"253\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/filter-examples-2.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/filter-examples-2.png 665w\"><\/figure>\n<p><strong>Step 7: <\/strong>If you choose to have a different name for&nbsp;<strong>Jenkinsfile<\/strong>, you can specify it in the build configuration.<\/p>\n<p>In the \u201cScript Path\u201d option, you can provide the required name. Ensure the Jenkinsfile is present in the repo with the same name you provide in the pipeline configuration.<\/p>\n<p>I am using <strong><code>multi-branch-pipeline\/Jenkinsfile<\/code><\/strong> becuase the Jenkinsfile is present in the multi-branch-pipeline folder.<\/p>\n<p>Also, Enable &#8220;Discard old builds&#8221; to keep only required build logs as shown below.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-32-14.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"677\" height=\"902\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-32-14.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-32-14.png 677w\"><\/figure>\n<p><strong>Step 8: <\/strong>Save all the job configurations.<\/p>\n<p>Jenkins&nbsp;<strong>scans the configured Github repo<\/strong>&nbsp;for all the branches&nbsp;and PR requests based on our configurations.<\/p>\n<p>The following image shows the job scanning the three branches, and since I haven\u2019t raised any pull request, Jenkins won\u2019t create any branch-based pipeline. I will show how to test the automatic pipeline creation after the webhook setup.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-33-12.png\" class=\"kg-image\" alt=\"multibranch pipeline initial repository scan\" loading=\"lazy\" width=\"754\" height=\"896\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-33-12.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-33-12.png 754w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>Till now, we have done configurations on the Jenkins side to scan branches based on the PR requests.<\/p>\n<p>To have a complete workflow, we need to configure a webhook in GitHub to send all repository events (commits, PRs, etc.) to Jenkins, so the pipelines can be triggered automatically.<\/p>\n<h2 id=\"configure-webhook-for-multibranch-pipeline\">Configure Webhook For Multibranch Pipeline<\/h2>\n<div class=\"kg-card kg-callout-card kg-callout-card-grey\">\n<div class=\"kg-callout-text\"><b><strong style=\"white-space: pre-wrap;\">Important Note:<\/strong><\/b> If you have a GitHub App created for Jenkins with webhook configuration and installed in the repositories, you don&#8217;t need to configure the webhook separately.<\/div>\n<\/div>\n<p>Follow the steps given below to setup the Jenkins webhook on the repo.<\/p>\n<p><strong>Step 1: <\/strong>Head over to the Github repo and click on the settings.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/github-settings-for-webhook-min-2.png\" class=\"kg-image\" alt=\"Github Jenkins webhook settings\" loading=\"lazy\" title=\"github settings for webhook-min\" width=\"996\" height=\"400\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/github-settings-for-webhook-min-2.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/github-settings-for-webhook-min-2.png 996w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p><strong>Step 2: <\/strong>Select the webhook option at the left and click \u201cAdd Webhook\u201d button.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/github-add-webhook-min-2.png\" class=\"kg-image\" alt=\"Github add Jenkins webhook\" loading=\"lazy\" title=\"Github Add Webhook-min\" width=\"989\" height=\"354\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/github-add-webhook-min-2.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/github-add-webhook-min-2.png 989w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p><strong>Step 3: <\/strong>dd your Jenkins URL followed by \u201c<strong><code>\/github-webhook\/<\/code><\/strong>\u201d under payload URL. Select the content type as \u201capplication\/json\u201d and click \u201cAdd Webhook\u201d<\/p>\n<div class=\"kg-card kg-callout-card kg-callout-card-grey\">\n<div class=\"kg-callout-text\"><b><strong style=\"white-space: pre-wrap;\">Note:&nbsp;<\/strong><\/b>You can choose what type of webhook you want to receive in Jenkins. For example, you want to trigger the pipeline only during PR; then, you can select just the PR event from the \u201cLet me select individual events\u201d option.<\/div>\n<\/div>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/create-github-webhook-for-multibranch-pipeline-min-2.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" title=\"create github webhook for multibranch pipeline-min\" width=\"633\" height=\"654\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/create-github-webhook-for-multibranch-pipeline-min-2.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/create-github-webhook-for-multibranch-pipeline-min-2.png 633w\"><\/figure>\n<p>You should see a green tick mark on a&nbsp;successful&nbsp;webhook configuration as shown below.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/jenkins-github-successful-webhook-delivery-min-2.png\" class=\"kg-image\" alt=\"Jenkins - Github Successful webhook delivery\" loading=\"lazy\" title=\"Jenkins - Github Successful webhook delivery-min\" width=\"749\" height=\"201\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/jenkins-github-successful-webhook-delivery-min-2.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/jenkins-github-successful-webhook-delivery-min-2.png 749w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>If you don\u2019t see a green tick or see a warning sign, click on the webhook link, scroll down to \u201cRecent Deliveries,\u201d and click on the last webhook. You should be able to view why the webhook delivery failed with the status code.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/troubleshoot-github-webhook-delivery-min-2.png\" class=\"kg-image\" alt=\"troubleshoot Github webhook delivery\" loading=\"lazy\" title=\"troubleshoot Github webhook delivery-min\" width=\"546\" height=\"346\"><\/figure>\n<p>Now we are done with all the required configurations for the multi-branch pipeline. The next step is to test the multi-branch pipeline workflow triggers.<\/p>\n<h2 id=\"test-multi-branch-pipeline\">Test Multi-branch Pipeline<\/h2>\n<p>This repo am using has two branches. <code>main<\/code> and <code>develop<\/code>.<\/p>\n<p>Update some content in the README file in the develop branch and raise a PR to main. You can also do this from a forked repository.<\/p>\n<p>It will send a webhook to Jenkins and and it will create a pipeline for the raised PR and starts building it.<\/p>\n<p>Now, if you check Jenkins you will find a pipeline for PR in Jenkins as shown below.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-38-10.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"590\" height=\"581\"><\/figure>\n<p>If the build fails, you can commit the changes to the develop branch and as long as the PR is open, it will trigger the PR pipeline.<\/p>\n<p>In the <strong><code>Jenkinfile<\/code><\/strong> I have added a condition to skip the deploy stage if the branch is develop and main if it is  a PR build. You can check that in the Jenkins build stages. If you check the stages you can clearly see the skipped deployment stages as shown below.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-39-10.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"620\" height=\"371\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-39-10.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-39-10.png 620w\"><\/figure>\n<p>Now if you merge the PR, <strong>Jenkins will trigger the main branch pipelin<\/strong> and executes all the deployment stages mentioned in the Jenkinsfile for the main branch.<\/p>\n<p>For example, in out pipeline example, we skip the dev and QA deployment if the branch is main. You can see that in the stages output.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-37-12.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"679\" height=\"299\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-37-12.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-37-12.png 679w\"><\/figure>\n<h2 id=\"enabling-pull-request-status-checks\">Enabling Pull Request Status Checks<\/h2>\n<p>With multi-branch pipeline, you can enable status checks. Meaning Jenkins reports the results back to GitHub as status checks. It appears on the PR page as shown below.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/checks-1.png\" class=\"kg-image\" alt=\"Jenkins reports the results back to GitHub as status checks\" loading=\"lazy\" width=\"760\" height=\"368\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/checks-1.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/checks-1.png 760w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>For example, developers may need status checks for the following.<\/p>\n<p>Common status checks might include:<\/p>\n<ol>\n<li>Build verification<\/li>\n<li>Unit tests<\/li>\n<li>Code style checks<\/li>\n<li>Security scans<\/li>\n<\/ol>\n<p>To enable these status checks in Github PR, you need to create create a Github App for Jenkins.<\/p>\n<p>You can follow this <a href=\"https:\/\/devopscube.com\/enable-jenkins-status-checks-github\/\">Github App for Jenkins<\/a> detailed guide to create one.<\/p>\n<p>Then in the multi-branch pipeline configuration, you need to use the Github App credential instead of username and password.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-40-8.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"1014\" height=\"670\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-40-8.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-40-8.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-40-8.png 1014w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<h2 id=\"troubleshooting-multibranch-pipelines\">Troubleshooting Multibranch Pipelines<\/h2>\n<p>I will talk about a few possible errors in a multibranch pipeline that you might encounter and how to troubleshoot them.<\/p>\n<p><strong>Branch Discovery Issue<\/strong>&nbsp;&nbsp;<\/p>\n<p>Sometimes even after creating new branches in the SCM, it might not reflect in the Jenkins pipeline. You can try running the &#8220;Scan Repository Now&#8221; option to scan the repo again. Also, check the repository scan configurations in the pipeline.<\/p>\n<p><strong>PR Webhooks Not Triggering the Pipelines<\/strong><\/p>\n<p>\u200bWhen a webhook is not triggering the pipeline, check the webhook delivery in Github for status code and error. Also, check if the Jenkins URL is correct. Also, check Jenkins logs from <code>Manage Jenkins --&gt; System Logs --&gt; All Jenkins logs<\/code>. If Jenkins is able to receive the webhook, the log should show the reason why the jobs are not getting triggered.<\/p>\n<p><strong>Commits Not Triggering Pipeline<\/strong><\/p>\n<p>If you want each commit to rigger the branch pipeline, then you should select the &#8220;<strong>Discover All Branches<\/strong> or &#8221; option in the branch discovery configuration. So whenever you commit a change to the discoverable branches or raise a PR, the pipeline will automatically get triggered.<\/p>\n<h2 id=\"multibranch-pipeline-best-practices\">Multibranch Pipeline Best Practices<\/h2>\n<p>Let&#8217;s have a look at some of the best practices for a multibranch pipeline.<\/p>\n<p><strong>Repo Branching&nbsp;<\/strong>\u2013 Have a Standard Structure<\/p>\n<p>It is essential to have the standard branching structure for your repositories. Whether it is your application code or infra code, having a standard branching will reduce the inconsistent configurations across different pipelines.<\/p>\n<p><strong>Shared Libraries<\/strong>&nbsp;\u2013 Reusable Pipeline Code<\/p>\n<p>Make use of&nbsp;<a href=\"https:\/\/devopscube.com\/jenkins-shared-library-tutorial\/\" rel=\"noreferrer\">shared libraries<\/a>&nbsp;for all your multi-branch pipelines. Reusable libraries make it easy to manage all the pipeline stages in a single place.&nbsp;<\/p>\n<p><strong>Pull Request Vs Commit Triggers<\/strong><\/p>\n<p>Try to use a PR based pipeline rather than commit based. If a code repo gets continuous commits it might overwhelm Jenkins with many builds.<\/p>\n<p>Commit based triggers are supported in PR based discovery as well. Here the commit trigger happens only when the PR is still open.<\/p>\n<h2 id=\"jenkins-pipeline-vs-multibranch-pipeline\">Jenkins Pipeline Vs. Multibranch Pipeline<\/h2>\n<p>A normal pipeline job is meant for building a single branch from the SCM and deploy to a single environment. However, you can<\/p>\n<p>A multibranch pipeline is meant for building multiple branches from a repository and deploy to multiple environments if required.<\/p>\n<p>A pipeline job supports both pipeline steps to be added in Jenkins configuration and form SCM.<\/p>\n<p>Use pipeline job for adhoc jobs, parameterised job executions and to debug pipeline as code.<\/p>\n<p>Do not use multibranch pipeline if you do not have a standard branching and CI\/CD strategy.<\/p>\n<h2 id=\"multibranch-pipeline-vs-github-organization-job\">Multibranch Pipeline Vs. Github Organization Job<\/h2>\n<p>Like a multi-branch pipeline, the Github organization folder is one of the Jenkins project types.<\/p>\n<div class=\"kg-card kg-callout-card kg-callout-card-grey\">\n<div class=\"kg-callout-text\"><b><strong style=\"white-space: pre-wrap;\">Note: <\/strong><\/b>The organization folder is not just limited to Github. It can be use used for <a href=\"https:\/\/about.gitlab.com\/?ref=devopscube.com\" rel=\"noreferrer noopener\">Gitlab<\/a>, <a href=\"https:\/\/bitbucket.org\/blog\/bitbucket-teams?ref=devopscube.com\" rel=\"noreferrer noopener\">Bitbucket teams<\/a>, or <a href=\"https:\/\/docs.gitea.io\/en-us\/?ref=devopscube.com\" rel=\"noreferrer noopener\">Gitea<\/a> organization.<\/div>\n<\/div>\n<p>Mullitbranch pipleine can only configure pipelines for a single Git repository. Whereas a Jenins Github organization project can automatically configure multi-branch pipelines for all the repos in a Github organization.<\/p>\n<p>It can discover all the repositories in the configured Github organization, with a Jenkinsfile.<\/p>\n<p>Also, you can configure a generic webhook in the organizational level to avoid having webhooks in each repo.<\/p>\n<p>The only difference between multi-branch and organization project is that organizations can configure multi-branch pipelines for multiple repos.<\/p>\n<p>So which one should I use?<\/p>\n<p>This totally depends on the workflow you need. If you have a standard pipeline and process of deploying applications or infra code, Github organization is great. Or else, configuring multibranch pipeline separately will be a good option.<\/p>\n<h2 id=\"i%E2%80%99d-like-to-hear-from-you\">I\u2019d like to hear from you<\/h2>\n<p>That\u2019s all for my guide to multi-branch pipelines.<\/p>\n<p>What type of Jenkins pipleines are you using?<\/p>\n<p>Do you think multi-branch pipeline will add value to your workflows?<\/p>\n<p>Or maybe you want stick to regular Jenkinsfile pipelines<\/p>\n<p>Either way, let me know by leaving a comment.<\/p>\n<hr>\n<p><strong>Ngu\u1ed3n:<\/strong> <a href=\"https:\/\/devopscube.com\/jenkins-multibranch-pipeline-tutorial\/\" target=\"_blank\" rel=\"noopener noreferrer\">Jenkins Multibranch Pipeline Tutorial For Beginners \u2014 DevOpsCube<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Source: https:\/\/devopscube.com\/jenkins-multibranch-pipeline-tutorial\/<\/p>\n","protected":false},"author":1,"featured_media":885,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-884","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops"],"_links":{"self":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/884","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=884"}],"version-history":[{"count":0,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/884\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/media\/885"}],"wp:attachment":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=884"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=884"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=884"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}