Gradle处理Git数据的最佳方法:如何正确获取当前Git分支名
Gradle 环境下稳定获取当前项目Git分支的可靠方案
核心解决思路
直接绕开两类已经踩过的坑:
- 直接弃用停更的
gradle-git插件,从根源上避开Gradle 6.6.1下的API兼容报错 - 执行Git命令的时候强制把工作目录锚定在Gradle项目根目录,不管CI从哪个路径触发构建,都不会出现找不到
.git目录的问题
可直接落地的原生实现
不需要引入任何第三方依赖,基于Gradle自带的Groovy能力编写工具方法,可直接兼容Gradle 6.6.1运行环境:
def getCurrentGitBranch() { // 锚定Gradle项目根目录为Git命令执行的工作路径 def repoRootDir = project.rootDir def process = new ProcessBuilder("git", "rev-parse", "--abbrev-ref", "HEAD") .directory(repoRootDir) .redirectErrorStream(true) .start() def output = process.inputStream.text.trim() def exitCode = process.waitFor() // 非Git仓库场景下不打断构建流程 if (exitCode != 0) { return "" } return output }
这套实现为什么能解决之前的问题
- 全程不需要引入任何第三方插件,不存在插件无人维护、和Gradle版本不兼容的问题,把代码贴到Gradle 6.6.1的脚本里就能直接跑
- 之前流传的通用实现是直接用JVM的默认工作目录跑Git命令,一旦CI从项目根目录的外部触发Wrapper,自然就找不到
.git;这套实现直接把Git命令的执行目录硬绑到project.rootDir,不管触发路径在哪,Git永远能找到仓库位置,不会报fatal: not a git repository的错
CI场景的兼容优化
Jenkins这类CI工具默认checkout代码的时候,经常会进入detached HEAD状态,这时候跑git rev-parse --abbrev-ref HEAD会返回没意义的HEAD字符串,根本拿不到真实分支名。可以给工具方法加一层优先读CI环境变量的逻辑:
def getCurrentGitBranch() { // 优先从CI自带的环境变量读取分支名,覆盖detached HEAD场景 def ciEnvBranch = System.getenv("BRANCH_NAME") ?: System.getenv("GIT_BRANCH") ?: System.getenv("CI_COMMIT_BRANCH") if (ciEnvBranch) { // 清理环境变量中常见的分支路径前缀 return ciEnvBranch.replace("refs/heads/", "") } def repoRootDir = project.rootDir def process = new ProcessBuilder("git", "rev-parse", "--abbrev-ref", "HEAD") .directory(repoRootDir) .redirectErrorStream(true) .start() def output = process.inputStream.text.trim() def exitCode = process.waitFor() if (exitCode != 0 || output == "HEAD") { return "" } return output }
优化后的逻辑优先读CI平台自带的分支环境变量,哪怕Git命令拿不到值也能兜底,本地开发和CI环境都能稳定拿到结果,全程没有额外依赖。
内容的提问来源于stack exchange,提问作者Swapnil Kotwal
相关产品推荐
相关产品推荐

