在windows上从Python3.x获取git标记

2024-06-06 21:24:17 发布

您现在位置:Python中文网/ 问答频道 /正文

我尝试过,但无法在Windows10上用Python 3.8完成一项看似微不足道的任务。 在PowerShell(core)中,我用不到2分钟的时间编写:

repo = "../micropython/git"
return (&git --git-dir=$repo describe --tags $(git --git-dir=$repo rev-list --tags='v[0-9].[0-9]*' --max-count=1))

结果是该分支所在的“v1.12”(或任何最新版本)

在花了太多时间在这个假定的oneliner上之后,使用python我根本无法得到任何结果

尝试:

# 1 feeding it the commandline as text 
cmd_str = "git --git-dir=../micropython/.git describe --tags $(git --git-dir=../micropython/.git rev-list --tags='v[0-9].[0-9]*' --max-count=1)"
subprocess.run( cmdstr , capture_output=True,shell=True)

#2 splitting the cmdline using shlex.split 

command_line = """
git describe --tags $(git rev-list --tags=\"v[0-9].[0-9]*\" --max-count=1)
"""
cmd = shlex.split(command_line)
x = subprocess.run( cmd, capture_output=True )
print(x)

# 3 using the 'gitpython' library
would not even import .... : see issue below

#4..20 
many variations of the above 

https://github.com/gitpython-developers/GitPython/issues/970

因此,作为一名开发人员,对我来说,最简单的方法似乎是从python到powershell(因为这是跨平台的),并获得依赖性

不过,我是在python而不是powershell中开始编写的,因为脚本是为python社区编写的(并且是一种学习体验),当然有一种方法可以以更类似于pylike的方式完成这项工作,甚至可能有点优雅

版本:

  • Microsoft Windows[版本10.0.19041.1]
  • git版本2.24.1.windows.2
  • Python 3.8.1

Tags: thegit版本cmdtruecountdirmicropython
1条回答
网友
1楼 · 发布于 2024-06-06 21:24:17

... surely there is a way to do this in a more pylike , and perhaps even somewhat elegant way?

优雅的在编码者的眼中。您可能会发现使用多种Git包装中的一种更为优雅。然而,您的第一种方法相对简单,有很多优点。如果有人(coughmecough)在其方便的测试系统上使用3.6作为基础版本,我们可以避免使用新的-in-3.7capture_output=True,并允许使用shell,这是$(...)扩展所必需的,这或多或少会让我们第一次尝试。但是我们可以利用 git-dir相当于在环境中设置GIT_DIR这一事实,这意味着我们不必在命令字符串中重复两次:

import os, subprocess

env = os.environ.copy()
env["GIT_DIR"] = "../micropython/.git"
cmd = "git describe  tags $(git rev-list  tags='v[0-9].[0-9]*'  max-count=1)"
ret = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    env=env, shell=True)

(当然,只要所有python都是3.7或更高版本,使用capture_output=True作为两个stdout/stderr的缩写就可以了)

请注意,我们必须保存结果。这就是为什么我们在这里有ret =来捕获结果。我们现在在ret中得到了结果:

>>> print(ret)
CompletedProcess(args="git describe  tags $(git rev-list  tags='v[0-9].[0-9]*'  max-count=1)", returncode=0, stdout=b'v2.24.0\n', stderr=b'')

注意retcode是零,也就是说,作为一个整体,这两个stdoutstderr字段是字节,而不是字符串。要解决此问题,我们可以在之后解码结果:

>>> print(ret.stdout.decode('utf-8'))
v2.24.0

>>> 

(假设输出是UTF-8)或让subprocess为我们做这件事。现代(3.7或更高版本)的方法是设置text=True,但由于在这台特定的机器上我仍然坚持使用3.6,所以我使用了旧的方法:

ret = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    env=env, shell=True, universal_newlines=True)

这将产生更有用的结果:

>>> print(ret)
CompletedProcess(args="git describe  tags $(git rev-list  tags='v[0-9].[0-9]*'  max-count=1)", returncode=0, stdout='v2.24.0\n', stderr='')

请注意,使用shell=Truerequires that you carefully vet any command you might runThe documentation还表示,在Windows上,您可以获得“环境变量COMSPEC”中的任何shell。使用默认shell=False并分别调用每个组件可能更明智:

import os, shlex, subprocess

env = os.environ.copy()
env["GIT_DIR"] = "../micropython/.git"

cmd = shlex.split("git rev-list  tags='v[0-9].[0-9]*'  max-count=1")
ret = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
if ret.returncode == 0:
    # Note: I tested this w/o using universal_newlines=True and it
    # worked fine, although the notion of adding a list of bytes to
    # a list of strings seems a bit odd.  This might not work well on
    # Windows; consider adding `text=True` or `universal_newlines=True`
    # above (and again below).
    cmd = shlex.split("git describe  tags") + [ret.stdout.strip()]
    ret = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)

此时ret再次适合检查:如果ret.returncode为零,ret.stdout具有来自git sdescribe的字节字符串。根据需要为文本翻译添加适当的字节

>>> print(ret)
CompletedProcess(args=['git', 'describe', ' tags', b'da72936f544fec5a335e66432610e4cef4430991'], returncode=0, stdout=b'v2.24.0\n', stderr=b'')

如果ret.returncode不是零,则git describe失败,或者前面的git rev-list失败。在ret.args中有失败的命令,在ret.returncode中有状态,在ret.stdout中有任何标准输出文本,在ret.stderr中有来自Git的任何错误消息

相关问题 更多 >