我想在我的模块中定义一个__version__
变量,该变量应该在git commit上自动更新,类似于SVN keywords。有没有办法在Git中实现它?有没有人有一个有效的例子?
我考虑使用GitPython,但我不想介绍另一个依赖项,我希望用户从SVN repo下载模块或作为zip包具有相同的版本控制方案(我不在乎这是一些难以辨认的哈希)。
编辑:我的特殊问题是我必须运行模拟,其结果取决于模拟脚本的确切版本。因此,每次我必须将版本号与模拟结果一起存储。如果两者都不同步,则可能会产生非常可怕的结果。
答案 0 :(得分:30)
最好将此作为包装的一部分,而不是在每次提交后执行。
有两个主要选项:
使用git-archive
打包,然后使用export-subst
attribute。不幸的是,你可以替代的东西仅限于git log --format=...
的占位符。例如,您可以在文件中编写__version__ = $Format:%H$
,将<filename> export-subst
放在.gitattributes中,当您运行git archive
时,可以将其更改为提交的完整哈希值'重新存档。这只是你要求的,但我更喜欢下一个选项。
自己做一个包装过程(通常是编译包的构建过程),并使用git describe
。这将为你提供一个漂亮的漂亮字符串,如v1.7.4.1-59-ge3d3f7d
,意思是“59提交超过标记v1.7.4.1
,在提交ge3d3f7d
”,然后你可以在某个地方插入代码中的正确位置你打包/构建。这就是Git本身所做的事情;结果被转储到一个文件中,该文件的内容被读入makefile,然后通过-D
预处理器选项传递给构建,并直接放入各种文件名(例如发布tarball)。
如果你真的,真的想在每次提交后都这样做,你可以使用post-commit钩子,但是只有你(以及那些你提供钩子的人)才会拥有它,而且很有可能获得它不同步 - 你还必须有一个post-checkout挂钩,依此类推。对于创建需要此版本号的任何进程来自己获取它真的更好。
你也可以使用涂抹/清洁过滤器,它更像你真正想要的(而不是简单地在每次提交后)。
答案 1 :(得分:5)
对于那些在2018年发现此问题的人,您也可以使用Versioneer。启用后,它将在构建时根据最新的Git标签自动在模块version
中的setup.py
和__version__
中设置{1>}。
例如,如果您在标签1.0.0
上构建项目,则Versioneer会将项目的版本设置为1.0.0。如果再执行两次提交,而无需检入就进行编辑,然后进行构建,则Versioneer会将版本设置为1.0.0+2.g1076c97.dirty
之类。
您当然可以自定义Versioneer识别为版本标签的标签。
这也是pandas和matplotlib等大型项目处理其版本控制的方式。
答案 2 :(得分:0)
除Versioneer之外的另一种可能性是setuptools_scm
。
通过在setup.py
中添加以下内容(或相应地对其进行修改),我已经成功实现了与OP非常相似的功能:
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
答案 3 :(得分:0)
您可以使用以下代码来检索当前的git提交版本(报告为分支上的提交ID或如果添加了标签,则为标签:
from git import Repo
def GetGitVersion():
'''report the git commit/branch/tag on which we are '''
repo = Repo(".", search_parent_directories=True)
git = repo.git
branchOrTag=git.rev_parse('--abbrev-ref', 'HEAD')
if branchOrTag == 'HEAD':
# get tag name
# since several tags are sometime put on the same commit we want to retrieve all of them
# and use the last one as reference
# Note:
# branchOrTag=`git describe --tags --exact-match` does not provided the latest created tag in case several point to the same place
currentSha=git.rev_parse('--verify','HEAD')
# list all tags on the current sha using most recent first:
allTags=git.tag('--points-at',currentSha,'--sort=-creatordate')
print (allTags)
allTagsArray=allTags.split(' ') #create an array (assuming tags are separated by space)
# if we checkouted a commit with no tag associated, the allTagsArray is empty we can use directly the sha value
if len(allTagsArray) == 0:
branchOrTag=git.rev-rev_parse('--short','HEAD') # take the short sha
else:
branchOrTag=allTagsArray[0] #first from the list
else:
#add the head commit id on the current branch
branchOrTag="{}[{}]".format(branchOrTag,git.rev_parse('--short', 'HEAD'))
return branchOrTag
if __name__ == "__main__":
print (GetGitVersion())
答案 4 :(得分:0)
(1)一种选择是从发布到已发布程序包中的发行版本中实时获取版本号。为此,您需要向__init__.py
添加一个依赖项,并使用类似setup.py
的方式发布产品,并在运行时执行python3 setup.py --version
。此方法使用the lightweight importlib_metadata module [importlib_metadata
(对于Python 3.8之前的版本)和importlib.metadata
(对于Python 3.8+)]:
from importlib.metadata import version, PackageNotFoundError
# pre-3.8 import statement
# from importlib_metadata import version, PackageNotFoundError
VERSION_FALLBACK = "0.0.0"
try:
__version__ = version(__name__)
except PackageNotFoundError:
# package is not installed
# assign signal or sane value as a default
__version__ = VERSION_FALLBACK
pass
这实现了PEP 566中的元数据推荐。如果您使用setuptools>=42.0.0
发行,则效果很好,也可以与其他工具发行的软件包一起使用。
(2)第二种选择是使用Git进行一些操作以收集最后的标记值(假设您正在标记应用程序)。然后增加点的版本号。然后用新值替换初始化文件中的值,并用新值标记。
# get and increment semantic version
version=$( git tag --list | sort -rV | head -1 ); # v0.1.1
version_point=${version##*.} # 1
version_point=$((${version_point} + 1)) # 2
version="${version%.*}.${version_point}" # v0.1.2
# replace in __init__.py (NOTE: THIS OVERWRITES!)
cat __init.py__ | sed -e "s/VERSION=.*/VERSION=${version}/i" > __init__.py
git add __init__.py && git commit -m "Updated version in __init__.py"
git tag -a ${version} -m "Latest tagged version"
答案 5 :(得分:0)
我的方法是将文件“version.txt”打包到包含命令输出的目录(比如“元数据”)中
git describe --long --tags --dirty --always >metadata/version.txt
连同 Python 源文件。
在运行 Python 应用程序的脚本中,有一个命令
export GIT_VERSION=`cat metadata/version.txt`
在应用程序启动之前运行。
代码可以在启动时运行
git_version = os.getenv('GIT_VERSION', None)
阅读