1. 概述

Jenkins 是一个强大的持续集成/持续交付(CI/CD)工具,广泛用于自动化软件交付流程。它与 Git 的集成非常紧密,允许我们在流水线中拉取代码、执行构建、测试和部署等操作。

在实际开发中,我们经常会遇到需要在一个 Jenkins Job 中检出多个 Git 仓库的场景。例如:

  • 多个微服务项目需要协同构建
  • 主项目依赖多个子模块仓库
  • 同时拉取前端和后端代码进行集成

本文将介绍如何在 Jenkins Pipeline 中:

✅ 检出单个 Git 仓库
✅ 将仓库检出到子目录中
✅ 同时检出多个仓库到不同子目录中


2. 使用 git 步骤检出仓库

Jenkins 提供了内置的 git 步骤,用于执行基本的 Git 操作,如 clone、checkout 分支等。

git 步骤是 Jenkins Git 插件的一部分,使用起来非常简单:

pipeline {
    agent any
    stages {
        stage("Checkout Repo") {
            steps {
                git url: "https://github.com/javaee-samples/javaee7-samples", branch: "master"
            }
        }
    }
}

这个步骤会将指定分支(这里是 master)的仓库内容检出到当前工作目录中。

检出完成后,你可以通过 Shell 命令查看目录内容:

$ ls
Dockerfile  batch        ejb          jacc      jaxrpc  jca  jsf   pom.xml     validation
LICENSE     cdi          el           jaspic    jaxrs   jms  json  servlet     websocket
README.md   concurrency  interceptor  javamail  jaxws   jpa  jta   test-utils

3. 使用 dir 步骤将仓库检出到子目录

有时我们不希望多个仓库都检出到根目录,避免文件冲突。此时可以使用 dir 步骤将操作限定在特定子目录下。

dir 步骤会创建一个指定名称的子目录,并在该目录下执行后续步骤:

pipeline {
    agent any
    stages {
        stage("Create Subdirectory") {
            steps {
                dir("myCheckoutDirectory") {
                    git url: "https://github.com/javaee-samples/javaee7-samples", branch: "master"
                }
            }
        }
    }
}

执行完成后,仓库内容将被检出到 myCheckoutDirectory 子目录中:

$ ls
myCheckoutDirectory
$ cd myCheckoutDirectory
$ ls
Dockerfile  cdi          interceptor  jaxrpc  jms   jta         validation
LICENSE     concurrency  jacc         jaxrs   jpa   pom.xml     websocket
README.md   ejb          jaspic       jaxws   jsf   test-utils
batch       el           javamail     jca     json  servlet

✅ 优点:结构清晰,适合多个仓库隔离
⚠️ 注意:dir 是控制路径的上下文,所有在其中的步骤都会在该目录下执行


4. 使用 checkout 步骤将仓库检出到子目录

除了 git + dir 的组合方式,我们还可以使用更强大的 checkout 步骤,它提供了更多定制选项。

其中一个关键参数是 RelativeTargetDirectory,可以指定检出目录:

pipeline {
    agent any
    stages {
        stage("Checkout to Subdir") {
            steps {
                checkout([
                    $class: 'GitSCM',
                    branches: [[name: 'master']],
                    doGenerateSubmoduleConfigurations: false,
                    extensions: [[
                        $class: 'RelativeTargetDirectory',
                        relativeTargetDir: 'MyNewCheckoutDirectory'
                    ]],
                    submoduleCfg: [],
                    userRemoteConfigs: [[
                        url: 'https://github.com/javaee-samples/javaee7-samples'
                    ]]
                ])
            }
        }
    }
}

执行完成后,仓库内容将被检出到 MyNewCheckoutDirectory 目录中:

$ ls
MyNewCheckoutDirectory
$ cd MyNewCheckoutDirectory
$ ls
Dockerfile  batch        ejb          jacc      jaxrpc  jca  jsf   pom.xml     validation
LICENSE     cdi          el           jaspic    jaxrs   jms  json  servlet     websocket
README.md   concurrency  interceptor  javamail  jaxws   jpa  jta   test-utils

✅ 优点:功能更强大,适合复杂场景
⚠️ 缺点:语法较复杂,不易快速上手


5. 同时检出多个仓库到不同子目录

这是本文的核心目标。我们可以将上面的逻辑封装成一个函数,动态传入仓库地址、分支、目标目录等参数。

✅ 方法一:使用 checkout 步骤封装函数

def myCheckoutFunction(branch, subdirectory, URL) {
    checkout([
        $class: 'GitSCM',
        branches: [[name: branch]],
        doGenerateSubmoduleConfigurations: false,
        extensions: [[
            $class: 'RelativeTargetDirectory',
            relativeTargetDir: subdirectory
        ]],
        submoduleCfg: [],
        userRemoteConfigs: [[url: URL]]
    ])
}

pipeline {
    agent any
    stages {
        stage("Checkout Multiple Repos") {
            steps {
                script {
                    myCheckoutFunction("master", "myFirstRepo", "https://github.com/javaee-samples/javaee7-samples")
                    myCheckoutFunction("master", "mySecondRepo", "https://github.com/javaee-samples/javaee8-samples.git")
                    myCheckoutFunction("master", "myThirdRepo", "https://github.com/javaee-samples/microprofile1.2-samples.git")
                }
            }
        }
    }
}

执行后目录结构如下:

$ ls
myFirstRepo  mySecondRepo  myThirdRepo

✅ 方法二:使用 git + dir 组合方式

def myCheckoutFunction(branch, subdirectory, URL) {
    dir(subdirectory) {
        git branch: branch, url: URL
    }
}

pipeline {
    agent any
    stages {
        stage("Checkout Multiple Repos") {
            steps {
                script {
                    myCheckoutFunction("master", "myFirstRepo", "https://github.com/javaee-samples/javaee7-samples")
                    myCheckoutFunction("master", "mySecondRepo", "https://github.com/javaee-samples/javaee8-samples.git")
                    myCheckoutFunction("master", "myThirdRepo", "https://github.com/javaee-samples/microprofile1.2-samples.git")
                }
            }
        }
    }
}

两种方式效果一致,区别在于语法风格和扩展性。


6. 总结

本文介绍了在 Jenkins Pipeline 中检出多个 Git 仓库的方法:

方法 步骤 说明
单仓库检出 git 最基础方式,适合简单场景
检出到子目录 dir + gitcheckout + RelativeTargetDirectory 推荐使用 dir 简洁易懂
多仓库并行检出 封装函数 + dir + gitcheckout 更加灵活,适合多模块项目

✅ 推荐做法:使用 dir + git 封装函数,结构清晰、易于维护
❌ 不推荐:将多个仓库直接检出到同一目录,容易造成文件冲突

如果你有多个项目需要集成构建,或者需要统一拉取前后端代码,这种多仓库检出方法非常实用。掌握它,可以让你的 Jenkins Pipeline 更加灵活和强大。


原始标题:Using a Jenkins Pipeline to Checkout Multiple Git Repos Into Same Job