基于uv构建的Python项目:如何在uv run及虚拟环境运行时自动获取带脏标记的Git哈希版本
基于uv构建的Python项目:如何在uv run及虚拟环境运行时自动获取带脏标记的Git哈希版本
我来分享几个适合你场景的实用方案,都是开发者们常用的实践,应该能解决你觉得步骤繁琐的问题:
方案1:运行时直接计算Git版本(零构建依赖,开发阶段首选)
这个方法完全跳过预生成版本文件的步骤,直接在代码里实时获取Git哈希和脏标记,最适合你日常用uv run的开发场景。
核心思路是:在应用入口代码里,调用Git命令或通过Git库读取仓库状态,不用任何构建钩子或额外步骤。
代码示例
在mypkg/myapp.py里加入版本获取逻辑:
import subprocess from pathlib import Path def get_git_version(): # 定位项目根目录(假设当前文件在src/mypkg下,根目录往上两级) repo_root = Path(__file__).parent.parent.parent try: # 获取短Git哈希 hash_result = subprocess.run( ["git", "rev-parse", "--short", "HEAD"], capture_output=True, text=True, cwd=repo_root, check=True ) git_hash = hash_result.stdout.strip() # 检查是否有未提交的修改(脏标记) status_result = subprocess.run( ["git", "status", "--porcelain"], capture_output=True, text=True, cwd=repo_root, check=True ) if status_result.stdout.strip(): git_hash += "-dirty" return git_hash except (subprocess.CalledProcessError, FileNotFoundError): # 处理Git不可用或不在仓库的情况 return "unknown (Git not accessible)" def main(): version = get_git_version() print(f"Usage: myapp ...") print(f"Version: {version}") # 你的应用业务逻辑...
优点
- 完全不需要构建步骤,
uv run myapp直接就能显示最新版本;如果用uv pip install -e .做可编辑安装,虚拟环境里直接运行myapp也能实时更新版本。 - 不用依赖任何第三方工具或构建钩子,代码简洁直观。
注意
如果是非可编辑模式安装(比如uv pip install .),安装后的代码在site-packages目录下,不在Git仓库范围内,这个方法就拿不到版本了。所以它更适合开发阶段,发布版本可以搭配下面的方案2。
方案2:用Versioningit + Hatch 覆盖全场景(开发+发布)
你之前试过Versioningit,它其实完全能解决你的问题,可能是没配置好可编辑模式的支持。它会在构建时生成固定版本,在可编辑安装时动态计算版本,完美覆盖uv run和uv pip install两种场景。
配置步骤
- 安装开发依赖:
uv add --dev versioningit hatchling
- 修改
pyproject.toml:
[project] dynamic = ["version"] # 让版本由versioningit动态生成 [tool.versioningit] vcs = "git" style = "short" # 使用短Git哈希 dirty-mark = "+dirty" # 脏状态的标记后缀 # 自动生成版本文件,供应用代码读取 write = {file = "src/mypkg/_version.py", template = "version = '{version}'"} [build-system] requires = ["hatchling", "versioningit"] build-backend = "hatchling.build" [tool.hatch.build.hooks.versioningit] enable = true # 启用Hatch的Versioningit构建钩子
- 在应用代码里读取版本:
try: # 优先从生成的版本文件读取 from mypkg._version import version except ImportError: # fallback到运行时计算(比如开发初期还没构建的情况) from mypkg.myapp import get_git_version version = get_git_version() def main(): print(f"Version: {version}")
效果
- 开发时:执行
uv pip install -e .做一次可编辑安装,之后无论是uv run myapp还是虚拟环境里直接运行myapp,都会自动显示最新的Git哈希+脏标记。 - 发布时:执行
uv build或uv pip install .,Versioningit会在构建时生成固定的版本号(包含当时的Git状态),打包到安装包中,运行时直接读取固定版本。
这个方案是最专业的,完全不用手动干预版本,覆盖所有使用场景。
方案3:自定义UV脚本别名(简化手动步骤)
如果你不想引入新工具,只是觉得之前的两步操作太繁琐,可以把生成版本文件和运行/安装的步骤封装成UV的自定义脚本,一键执行。
在pyproject.toml里添加:
[tool.uv.scripts] # 一键运行应用(自动先更新版本文件) run = "python write_version_to_file.py && uv run myapp" # 一键安装应用(自动先更新版本文件) install = "python write_version_to_file.py && uv pip install --force-reinstall ."
之后你只需要执行:
# 一键运行应用 uv run run # 一键安装应用 uv run install
就自动完成了版本文件生成+运行/安装的两步操作,不用手动敲两个命令,也不用记复杂参数。
总结
- 如果你主要是开发阶段用,优先选方案1,零依赖最省心。
- 如果需要兼顾开发和发布场景,选方案2,自动化程度最高且专业。
- 如果你不想改代码或加依赖,选方案3,用别名简化操作流程。
备注:内容来源于stack exchange,提问作者Bioman
相关产品推荐
相关产品推荐

