Docker中.git被忽略时,如何用SETUPTOOLS_SCM_PRETEND_VERSION获取版本
问题背景
使用setuptools_scm动态生成Python包版本号,pyproject.toml中配置了dynamic = ["version"]。Docker构建时,因.dockerignore忽略了**/.git导致构建失败;取消忽略虽能成功,但不想复制整个.git目录到镜像中。尝试通过构建参数传递版本号并使用SETUPTOOLS_SCM_PRETEND_VERSION变量未生效,需要可行方案。
可行解决方案
方案一:正确使用SETUPTOOLS_SCM_PRETEND_VERSION环境变量
你的Dockerfile中错误地在安装命令中尝试运行python -m setuptools_scm(此时无git仓库,该命令必然失败),实际上只需直接用构建传入的VERSION参数设置SETUPTOOLS_SCM_PRETEND_VERSION即可,setuptools_scm会直接使用该变量值作为版本号。
修改Dockerfile中的安装步骤:
# 移除不必要的ENV VERSION=$VERSION ARG VERSION # 直接用构建参数设置setuptools_scm的模拟版本变量 RUN SETUPTOOLS_SCM_PRETEND_VERSION=${VERSION} pip install --root-user-action=ignore --no-cache-dir --no-deps .
构建脚本无需修改,依然通过--build-arg VERSION=${VERSION}传递版本号即可。
方案二:提前生成版本文件(更稳定)
在Docker构建前,本地生成包含版本信息的文件,让setuptools_scm在Docker中无需依赖git即可读取版本。
- 修改
pyproject.toml的setuptools_scm配置,指定版本文件输出路径:
[tool.setuptools_scm] write_to = "my_package/_version.py"
- 修改构建脚本,提前在本地生成版本文件:
#!/usr/bin/env bash set -e source vars.env VERSION=$(git describe --tags --dirty --always) # 本地生成版本文件,无需git进入Docker上下文 python -m setuptools_scm git submodule update --init --recursive --progress docker build \ --progress=plain \ -t "${DOCKER_IMAGE_NAME}:${VERSION}" \ .
- Dockerfile中无需处理版本参数,直接执行安装命令即可:
RUN pip install --root-user-action=ignore --no-cache-dir --no-deps .
此时setuptools_scm会自动读取生成的_version.py文件中的版本信息,无需git仓库支持。
方案三:仅复制必要的git文件(不推荐)
如果必须让setuptools_scm在Docker中直接检测版本,可只复制git仓库的必要文件而非整个.git目录,修改.dockerignore:
**/.git/* !**/.git/HEAD !**/.git/refs
这样COPY . .会复制HEAD和refs目录,setuptools_scm可据此生成版本号。但该方法依赖git仓库结构,后续git版本更新可能导致兼容性问题,不推荐长期使用。
总结
推荐优先使用方案一(简单直接)或方案二(稳定可靠),避免复制不必要的git文件到Docker镜像中,同时保证版本号正常生成。
内容的提问来源于stack exchange,提问作者Anil

