How to Access Git Branch Information in Declarative Jenkins Pipelines: A Complete Guide


2 views

When working with declarative Jenkins pipelines, accessing Git branch information can be tricky. The main issue stems from Jenkins checking out specific commits rather than branches, resulting in a detached HEAD state. This makes traditional methods like git branch unreliable.

The most reliable approach is to use the return value of the checkout step. Here's a working example:

pipeline {
  agent any
  stages {
    stage('Get Git Info') {
      steps {
        script {
          def scmVars = checkout([
            $class: 'GitSCM',
            branches: [[name: '*/master']],
            userRemoteConfigs: [[url: 'https://github.com/your/repo.git']],
            extensions: []
          ])
          env.GIT_BRANCH = scmVars.GIT_BRANCH
          env.GIT_COMMIT = scmVars.GIT_COMMIT
        }
        
        sh '''
          echo "Branch: ${GIT_BRANCH}"
          echo "Commit: ${GIT_COMMIT}"
        '''
      }
    }
  }
}

For more complex scenarios, you might want to combine this with credentials:

pipeline {
  agent any
  stages {
    stage('Build') {
      steps {
        withCredentials([usernamePassword(
          credentialsId: 'git-creds',
          usernameVariable: 'GIT_USER',
          passwordVariable: 'GIT_PASS'
        )]) {
          script {
            def scmVars = checkout([
              $class: 'GitSCM',
              branches: [[name: '*/${BRANCH_NAME}']],
              userRemoteConfigs: [[
                url: 'https://github.com/your/repo.git',
                credentialsId: 'git-creds'
              ]]
            ])
            env.GIT_BRANCH_NAME = scmVars.GIT_BRANCH.replace('origin/', '')
          }
        }
        
        echo "Building branch: ${env.GIT_BRANCH_NAME}"
      }
    }
  }
}

For multibranch pipelines, Jenkins automatically sets some environment variables:

pipeline {
  agent any
  stages {
    stage('Build') {
      steps {
        sh '''
          echo "BRANCH_NAME: ${BRANCH_NAME}"
          echo "CHANGE_ID: ${CHANGE_ID}"
          echo "CHANGE_TARGET: ${CHANGE_TARGET}"
        '''
      }
    }
  }
}

Detached HEAD state: If you need the actual branch name, use the checkout return value method shown above rather than running git branch commands.

Environment variables not available: Remember that SCM-specific variables aren't automatically available as environment variables - you need to explicitly capture them from the checkout step.

Multibranch pipelines: In multibranch projects, Jenkins provides BRANCH_NAME automatically, but this won't be available in regular pipelines.

Here's how you might use the branch information to create different output files:

pipeline {
  agent any
  stages {
    stage('Build') {
      steps {
        script {
          def scmVars = checkout scm
          def shortBranch = scmVars.GIT_BRANCH.replace('origin/', '')
          env.OUTPUT_FILE = "build-${shortBranch}.tar.gz"
        }
        
        sh '''
          tar -czf ${OUTPUT_FILE} .
          echo "Created artifact: ${OUTPUT_FILE}"
        '''
      }
    }
  }
}

When working with declarative Jenkins pipelines, many developers face difficulties accessing Git metadata like branch names. The fundamental issue stems from Jenkins checking out specific commits rather than branches, resulting in detached HEAD states that obscure branch information.

Here's a production-tested approach that properly captures Git variables in declarative pipelines:

pipeline {
  agent any
  environment {
    GIT_BRANCH = ""
  }
  stages {
    stage('Checkout') {
      steps {
        script {
          def scmVars = checkout([
            $class: 'GitSCM',
            branches: [[name: '*/main']],
            extensions: [],
            userRemoteConfigs: [[url: 'your-repo-url']]
          ])
          env.GIT_BRANCH = scmVars.GIT_BRANCH
          env.GIT_COMMIT = scmVars.GIT_COMMIT
        }
      }
    }
    stage('Build') {
      steps {
        sh '''
          echo "Building branch: ${GIT_BRANCH}"
          echo "Commit hash: ${GIT_COMMIT}"
        '''
      }
    }
  }
}

The checkout step returns a map containing these useful Git variables:

  • GIT_BRANCH: The full branch ref (e.g., refs/heads/main)
  • GIT_COMMIT: The full commit hash
  • GIT_PREVIOUS_COMMIT: Previous build's commit hash
  • GIT_URL: Repository URL

For cleaner branch names without the "refs/heads/" prefix:

script {
  def scmVars = checkout(scm)
  env.BRANCH_NAME = scmVars.GIT_BRANCH.replaceAll('refs/heads/', '')
}

For pipelines using the scm directive:

pipeline {
  agent any
  stages {
    stage('Build') {
      steps {
        script {
          checkout(scm)
          def branch = env.BRANCH_NAME ?: sh(
            script: 'git rev-parse --abbrev-ref HEAD',
            returnStdout: true
          ).trim()
          echo "Building branch: ${branch}"
        }
      }
    }
  }
}

If you're still getting null values:

  1. Ensure your Jenkins Git plugin is updated (minimum v3.9.0)
  2. Verify your pipeline has the SCM configuration properly set
  3. Check Jenkins logs for any Git-related warnings
  4. Consider using the withCredentials block if authentication fails

This example shows branch-dependent behavior:

stage('Deploy') {
  when {
    expression { 
      env.GIT_BRANCH == 'refs/heads/main' 
    }
  }
  steps {
    sh 'make deploy-production'
  }
}