如何用git重写python __version__?
6 个回答
对于2018年看到这个问题的人,你可以使用Versioneer。一旦启用,它会自动根据构建时最新的Git标签来设置setup.py
中的version
和你模块中的__version__
。
举个例子,如果你在标签1.0.0
时构建你的项目,Versioneer会把项目的版本设置为1.0.0。如果你再做两个提交,编辑一些内容但没有提交,然后再构建,Versioneer会把版本设置为类似1.0.0+2.g1076c97.dirty
这样的格式。
当然,你可以自定义Versioneer识别哪些标签作为版本标签。
这也是像pandas和matplotlib这样的大型项目处理版本控制的方式。
除了Versioneer,还有一个选择是setuptools_scm
。
我成功地实现了一个和提问者很相似的功能,方法是往setup.py
里添加了以下内容(或者根据需要进行修改):
from setuptools import setup
setup(
...,
use_scm_version=True,
setup_requires=['setuptools_scm'],
...,
)
为了让__version__
能够自动更新,我还在我包的__init__.py
里添加了这个:
from pkg_resources import get_distribution, DistributionNotFound
try:
__version__ = get_distribution(__name__).version
except DistributionNotFound:
# package is not installed
pass
把这个功能放在打包的时候做,可能比每次提交后都做要好。
主要有两个选择:
使用
git-archive
来打包,并使用export-subst
属性。不过,能替换的内容有限,只能用git log --format=...
中的占位符。例如,你可以在文件中写__version__ = $Format:%H$
,然后在 .gitattributes 文件里加上<filename> export-subst
,当你运行git archive
时,这个内容会被替换成你正在打包的提交的完整哈希值。这基本上就是你想要的,但我更喜欢下一个选项。自己在打包过程中做这件事(通常是在编译包的构建过程中),并使用
git describe
。这样你可以得到一个漂亮的字符串,比如v1.7.4.1-59-ge3d3f7d
,意思是“在标签v1.7.4.1
之后的59次提交,当前提交是ge3d3f7d
”。然后你可以把这个字符串放到代码的合适位置,作为打包/构建的一部分。这就是Git本身的做法;结果会被写入一个文件,内容会被读取到makefile中,然后通过-D
预处理选项传递到构建过程中,并直接放入各种文件名中(比如发布的压缩包)。
如果你真的想在每次提交后都做这个,可以使用一个提交后钩子,但那样只有你(和你给钩子的人)能用,而且很可能会出现不同步的情况——你还需要一个检出后钩子,等等。其实,最好是让需要这个版本号的过程自己去获取。
你也可以使用一个模糊/清理过滤器,这样会更接近你实际想要的效果(而不是单纯在每次提交后)。