Automation

Configure Multi-Branch Pipeline in Jenkins

Jenkins multibranch pipelines automatically discover branches in a Git repository and create a pipeline job for each branch that contains a Jenkinsfile. This removes the need to manually create and manage separate jobs for every feature branch, hotfix, or release branch – Jenkins handles it all through source control.

Original content from computingforgeeks.com - post 96728

This guide covers setting up a Jenkins multibranch pipeline from scratch. We walk through plugin installation, Jenkinsfile creation, branch source configuration for GitHub/GitLab/Bitbucket, webhook triggers, parallel stages, branch-specific deploy logic, and stale branch cleanup.

Prerequisites

Before starting, make sure you have the following in place:

  • Jenkins 2.x installed and running – if you need to set this up, see our guide on installing Jenkins
  • Admin access to your Jenkins instance
  • A Git repository (GitHub, GitLab, or Bitbucket) with at least one branch
  • Git installed on the Jenkins server
  • Network access from Jenkins to your Git provider (port 443 for HTTPS, port 22 for SSH)

Step 1: Install Required Jenkins Plugins

Multibranch pipelines need a few core plugins. Most Jenkins installations include these by default, but verify they are installed and up to date.

Navigate to Manage Jenkins > Plugins > Available plugins and install these if missing:

  • Pipeline – core pipeline engine for Jenkinsfile execution
  • Pipeline: Multibranch – enables multibranch pipeline job type
  • Git – Git SCM integration
  • GitHub Branch Source – for GitHub repositories
  • GitLab Branch Source – for GitLab repositories
  • Bitbucket Branch Source – for Bitbucket repositories
  • Blue Ocean (optional) – modern pipeline visualization UI

You can also install plugins from the CLI. SSH into your Jenkins server and run:

jenkins-plugin-cli --plugins "workflow-multibranch git github-branch-source gitlab-branch-source blueocean"

After installing plugins, restart Jenkins to activate them:

sudo systemctl restart jenkins

Confirm Jenkins is back up:

sudo systemctl status jenkins

The service should show active (running) within a few seconds.

Step 2: Create a Jenkinsfile in Your Repository

The Jenkinsfile defines your pipeline stages and lives in the root of your Git repository. Jenkins reads this file from each branch to determine what to build and how.

Create a file named Jenkinsfile (no extension) in your repository root with this basic structure:

pipeline {
    agent any

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Build') {
            steps {
                echo 'Building the application...'
                // Replace with your actual build commands
                sh 'make build || echo "No Makefile, skipping build"'
            }
        }

        stage('Test') {
            steps {
                echo 'Running tests...'
                sh 'make test || echo "No tests defined, skipping"'
            }
        }

        stage('Deploy') {
            when {
                branch 'main'
            }
            steps {
                echo 'Deploying to production...'
                // Add your deployment commands here
            }
        }
    }

    post {
        success {
            echo 'Pipeline completed successfully.'
        }
        failure {
            echo 'Pipeline failed. Check the logs above.'
        }
    }
}

This Jenkinsfile runs Checkout, Build, and Test stages on every branch. The Deploy stage only runs on the main branch thanks to the when { branch 'main' } condition. Commit and push this file to your repository.

Step 3: Create a Multibranch Pipeline Job in Jenkins

With the Jenkinsfile in your repo, create the multibranch pipeline job in Jenkins.

  1. From the Jenkins dashboard, click New Item
  2. Enter a name for the job (e.g., my-app-pipeline)
  3. Select Multibranch Pipeline and click OK
  4. You are taken to the job configuration page where you set up branch sources

The job configuration has three key sections: Branch Sources (where to find your code), Build Configuration (how to find the Jenkinsfile), and Scan Triggers (how often to check for new branches).

Step 4: Configure Branch Sources

Branch sources tell Jenkins where your Git repository lives and how to authenticate. The configuration varies slightly depending on your Git provider.

GitHub Repository

  1. In the job configuration, click Add source > GitHub
  2. Under Credentials, add a GitHub Personal Access Token (PAT) with repo scope. Click Add > Jenkins, select Username with password, enter your GitHub username and the PAT as the password
  3. Set Repository HTTPS URL to your repo URL, e.g., https://github.com/your-org/your-repo.git
  4. Under Behaviors, keep the defaults: Discover branches, Discover pull requests from origin, Discover pull requests from forks

GitLab Repository

  1. Click Add source > GitLab Project
  2. Set the Server URL to your GitLab instance (e.g., https://gitlab.com or your self-hosted URL)
  3. Add credentials using a GitLab Personal Access Token with api and read_repository scopes
  4. Select the Owner (namespace) and Project from the dropdowns

If you run a self-hosted GitLab CE instance, make sure Jenkins can reach it over the network and the SSL certificate is trusted by your Jenkins JVM.

Bitbucket Repository

  1. Click Add source > Bitbucket
  2. Add credentials using a Bitbucket App Password with Repositories: Read permission
  3. Enter the Repository Owner and Repository Name

After configuring any branch source, click Save. Jenkins immediately scans the repository and creates pipeline jobs for every branch that contains a Jenkinsfile.

Step 5: Configure Build Triggers

By default, Jenkins only scans for new branches and changes when you manually trigger a scan. For automated CI/CD, configure webhooks or polling.

Webhook Triggers (Recommended)

Webhooks notify Jenkins immediately when code is pushed. This is faster and more efficient than polling.

For GitHub:

  1. Go to your GitHub repo > Settings > Webhooks > Add webhook
  2. Set Payload URL to https://your-jenkins-url/github-webhook/
  3. Set Content type to application/json
  4. Select Just the push event (or add Pull Request events if needed)
  5. Click Add webhook

For GitLab:

  1. Go to your GitLab project > Settings > Webhooks
  2. Set URL to https://your-jenkins-url/project/your-job-name
  3. Check Push events and Merge request events
  4. Click Add webhook

Make sure your Jenkins instance is accessible from the internet (or from your Git provider’s network). If Jenkins is behind a firewall, open port 8080 (or your configured port) for incoming webhook traffic, or use a reverse proxy on port 443.

SCM Polling (Fallback)

If webhooks are not possible (e.g., Jenkins is on a private network), use SCM polling as a fallback. In the multibranch pipeline configuration under Scan Multibranch Pipeline Triggers, check Periodically if not otherwise run and set an interval.

A 2-minute interval works for active development. For less active repos, 5-15 minutes reduces load on your Git server:

  • 1 minute – high-frequency, adds load to Git server
  • 2 minutes – good balance for active repos
  • 5 minutes – reasonable for most teams
  • 15 minutes – low priority repos

Step 6: Jenkinsfile Best Practices

A well-structured Jenkinsfile makes your pipeline readable, maintainable, and fast. Here are patterns that work well in production.

Parallel Stages

Run independent tasks at the same time to cut total pipeline duration. Use parallel inside a stage to execute multiple sub-stages concurrently:

stage('Test') {
    parallel {
        stage('Unit Tests') {
            steps {
                sh 'make unit-test'
            }
        }
        stage('Integration Tests') {
            steps {
                sh 'make integration-test'
            }
        }
        stage('Lint') {
            steps {
                sh 'make lint'
            }
        }
    }
}

Unit tests, integration tests, and linting run simultaneously. If any parallel stage fails, the entire Test stage fails.

When Conditions for Branch Filtering

The when directive controls which branches execute a stage. This is how you prevent feature branches from triggering production deployments:

stage('Deploy to Staging') {
    when {
        branch 'develop'
    }
    steps {
        sh './deploy.sh staging'
    }
}

stage('Deploy to Production') {
    when {
        branch 'main'
    }
    steps {
        sh './deploy.sh production'
    }
}

You can also match branch patterns with glob expressions:

stage('Deploy to QA') {
    when {
        branch 'release/*'
    }
    steps {
        sh './deploy.sh qa'
    }
}

This runs the QA deploy stage only on branches matching the release/* pattern (e.g., release/1.2, release/2.0).

Environment Variables and Credentials

Define environment variables at the pipeline level and use Jenkins credentials for secrets. Never hardcode passwords or API keys in your Jenkinsfile:

pipeline {
    agent any

    environment {
        APP_ENV = 'production'
        DOCKER_REGISTRY = 'registry.example.com'
        DOCKER_CREDS = credentials('docker-registry-creds')
    }

    stages {
        stage('Build Image') {
            steps {
                sh 'docker build -t $DOCKER_REGISTRY/myapp:$BUILD_NUMBER .'
                sh 'echo $DOCKER_CREDS_PSW | docker login $DOCKER_REGISTRY -u $DOCKER_CREDS_USR --password-stdin'
                sh 'docker push $DOCKER_REGISTRY/myapp:$BUILD_NUMBER'
            }
        }
    }
}

The credentials() helper fetches stored credentials from Jenkins. For username/password credentials, Jenkins automatically creates _USR and _PSW variables. If you are building Jenkins in a Docker container, make sure the Docker socket is mounted or use Docker-in-Docker.

Step 7: Branch-Specific Pipeline Behavior

In real projects, different branches serve different purposes. Feature branches need tests, develop needs staging deployment, and main needs production deployment. Here is a complete Jenkinsfile that handles all three:

pipeline {
    agent any

    environment {
        APP_NAME = 'myapp'
        DOCKER_REGISTRY = 'registry.example.com'
    }

    stages {
        stage('Build') {
            steps {
                sh 'docker build -t $DOCKER_REGISTRY/$APP_NAME:$BRANCH_NAME-$BUILD_NUMBER .'
            }
        }

        stage('Test') {
            steps {
                sh 'docker run --rm $DOCKER_REGISTRY/$APP_NAME:$BRANCH_NAME-$BUILD_NUMBER make test'
            }
        }

        stage('Deploy to Staging') {
            when {
                branch 'develop'
            }
            steps {
                echo 'Deploying to staging environment...'
                sh './scripts/deploy.sh staging $BRANCH_NAME-$BUILD_NUMBER'
            }
        }

        stage('Approval') {
            when {
                branch 'main'
            }
            steps {
                input message: 'Deploy to production?', ok: 'Deploy'
            }
        }

        stage('Deploy to Production') {
            when {
                branch 'main'
            }
            steps {
                echo 'Deploying to production...'
                sh './scripts/deploy.sh production $BRANCH_NAME-$BUILD_NUMBER'
            }
        }
    }

    post {
        always {
            cleanWs()
        }
        failure {
            echo "Build failed on branch: ${env.BRANCH_NAME}"
            // Add notification: Slack, email, etc.
        }
    }
}

Key points in this pipeline:

  • $BRANCH_NAME is a built-in environment variable Jenkins provides for multibranch pipelines
  • The input step pauses the pipeline and waits for manual approval before production deploy
  • cleanWs() in the post block removes workspace files after every run to prevent disk bloat
  • Feature branches only run Build and Test – no deploy stages execute

Step 8: Clean Up Old Branches

Merged and deleted branches leave behind stale pipeline jobs in Jenkins. Over time, these pile up and consume disk space. Configure automatic cleanup in the multibranch pipeline configuration.

Orphaned Item Strategy

In the job configuration under Orphaned Item Strategy, set:

  • Discard old items – checked
  • Days to keep old items – 7 (keeps branch jobs for a week after the branch is deleted from Git)
  • Max # of old items to keep – 20 (hard cap on stale jobs)

When Jenkins scans the repository and no longer finds a branch, it marks the job as orphaned. After the configured retention period, the orphaned job and its build history are automatically deleted.

Build Rotation in Jenkinsfile

Control how many builds Jenkins keeps per branch directly in the Jenkinsfile using the options block:

pipeline {
    agent any

    options {
        buildDiscarder(logRotator(numToKeepStr: '10', daysToKeepStr: '30'))
        disableConcurrentBuilds()
        timeout(time: 30, unit: 'MINUTES')
    }

    stages {
        // your stages here
    }
}

This keeps the last 10 builds or builds from the last 30 days (whichever is more restrictive). The disableConcurrentBuilds() option prevents the same branch from running two builds at the same time, which avoids race conditions during deployment. The timeout option kills stuck builds after 30 minutes.

Jenkins Multibranch Pipeline Jenkinsfile Directives Reference

This table summarizes the most commonly used Jenkinsfile directives for multibranch pipelines.

DirectivePurposeExample
pipelineTop-level block wrapping the entire pipelinepipeline { agent any; stages { ... } }
agentWhere the pipeline runs (any node, specific label, Docker image)agent { docker { image 'node:20' } }
stagesContainer for all stage blocksstages { stage('Build') { ... } }
stageNamed group of stepsstage('Test') { steps { sh 'make test' } }
stepsActual commands to executesteps { sh 'npm install' }
whenConditional execution based on branch, environment, or expressionwhen { branch 'main' }
parallelRun multiple stages concurrentlyparallel { stage('A') {...} stage('B') {...} }
environmentSet environment variables for the pipeline or a stageenvironment { DB_HOST = '10.0.1.5' }
optionsPipeline-level settings (timeout, retry, build rotation)options { timeout(time: 30, unit: 'MINUTES') }
postActions after pipeline completes (always, success, failure)post { failure { mail to: '[email protected]' } }
inputPause for manual approvalinput message: 'Deploy?', ok: 'Yes'
credentials()Fetch stored Jenkins credentials as environment variablesCREDS = credentials('my-cred-id')
triggersDefine automated build triggerstriggers { pollSCM('H/5 * * * *') }
parametersDefine user-input parameters for the pipelineparameters { string(name: 'ENV', defaultValue: 'dev') }

Conclusion

You now have a fully configured Jenkins multibranch pipeline that automatically discovers branches, runs tests, and deploys based on branch name. The Jenkinsfile lives in your repo alongside your code, so pipeline changes go through the same code review process as application changes.

For production use, add SSL/TLS termination in front of Jenkins, enable LDAP or SSO authentication, set up Slack or email notifications in the post block, and back up your Jenkins home directory regularly. If your CI/CD pipeline builds container images, consider integrating with Gitea or a private registry for tighter control over your artifact lifecycle.

Related Articles

Automation How To Install Terraform oVirt / RHEV Plugin Automation How To Install JFrog Artifactory on Ubuntu 20.04 Automation Install and Use KubeSphere on existing Kubernetes cluster Automation How To Store Terraform State in Consul KV Store

Leave a Comment

Press ESC to close