从python子流程调用gitlog时忽略decoraterefs选项

2024-03-29 12:59:25 发布

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

我被这个错误难住了。我尝试过搜索很多东西,我尝试过使用调试器跟踪调用。我一点也不明白

我的问题:

我从命令行运行这个命令

git log --format=format:%D --simplify-by-decoration --decorate-refs=*platVer*

我得到了预期的标签列表

tag: platVer/222.3.4123, tag: myplatVer-222.3.4123
tag: platVer-20.07.000
tag: platVer-20.06.000
tag: platVer-20.05.000

如果我在命令行上从python运行这个命令,我也会得到预期的列表

>>> from subprocess import call, Popen, PIPE
>>> pp = Popen(['git', 'log', '--decorate-refs=*platVer*', '--format=format:%D', '--simplify-by-decoration'])
tag: platVer/222.3.4123, tag: myplatVer-222.3.4123
tag: platVer-20.07.000
tag: platVer-20.06.000
tag: platVer-20.05.000

在空闲或脚本中运行此行时,输出未被捕获(如预期),要启用标准输出的捕获,popen需要将标准输出参数设置为管道

但是如果我使用stdout=PIPE运行,它似乎会忽略'--decorate-refs=*platVer*',只列出整个引用集

>>> pp = Popen(['git', 'log', '--decorate-refs=*platVer*', '--format=format:%D', '--simplify-by-decoration'], stdout=PIPE)
>>> pp.stdout.read()
b'HEAD -> feature/ps2python, origin/feature/ps2python\ntag: platVer/222.3.4123, tag: myplatVer-222.3.4123, tag: mao_test ....

当我从脚本或在空闲状态下运行它时,会得到相同的结果

from subprocess import Popen, PIPE

pp = Popen(['git', 'log', '--decorate-refs=*platVer*', '--format=format:%D', '--simplify-by-decoration'], stdout=PIPE)
print( pp.stdout.read().decode('ascii' ) )

给我这个

HEAD -> feature/ps2python, origin/feature/ps2python
tag: platVer/222.3.4123, tag: myplatVer-222.3.4123, tag: mao_test
show-current, develop
tag: platVer-20.07.000,
... (cut the remaining many many lines of refs)

我运行的是windows 10(版本10.0.18363.778) git版本2.29.2.windows.2 python版本3.8.5

我试过shell=Tre/False,universal\u newlines=True/False 我在WSL(ubuntu)上试过了 结果都一样

然后我尝试了一个虚拟的ubuntu 18.LTS。使用git版本2.17。这里我得到了有线结果,其中'--decorate-refs=*platVer*'被忽略。从命令行

然后我在这个ubuntu上将git更新到了更新的版本(2.29.2)。现在命令完全按照预期工作

然后,我从python中尝试了相同的命令,结果与在win10机器上相同

请帮忙。无法理解设置stdout=PIPE如何更改git命令的行为

编辑: 我确实检查了git的同一版本是否调用了管道

Edit2:

我把@torek的答案标记为被接受的答案,因为它完美地解决了我的问题

然而,我应该说明我使用git日志的目标,以便得到更广泛的答案

My goal is to find the tag that is the first tag found when traveling back in history (topological or graph ordering) and that matches a regular expression.

我以前使用的是rev list,但没有发现可以按照我想要的顺序交付标签的文档,也许我遗漏了什么

当我同时声明需要一个正则表达式匹配时,我在命令中使用一个简单的glob模式的原因是,我假设globbing更快,因此使用它作为一个预过滤器来缩短python中正则表达式需要解析的列表。我预计在几年内,标签列表将包含1000多个标签,并且会不断增长。其中带有“platVer”一词的标签约占该列表的1%


Tags: git命令版本logformat列表tagstdout
1条回答
网友
1楼 · 发布于 2024-03-29 12:59:25

decorate=full decorate=short添加到git log参数中。您也可以使用 decorate=true decorate=1,但是fullshort是这些天记录的值。Full包括全名(例如,refs/heads/somebranch),而short缩短为分支或标记名

长(但可选)有用的背景信息

默认的log.decorate设置是auto(反正是从Git2.9开始的;在此之前是no/0/false,在不同的地方引入了各种错误,然后在以后的版本中修复;从Git2.13开始,它一直是稳定的)。auto设置意味着如果人类正在读取输出,no如果程序正在读取输出1

装饰本身是必需的(即必须打开),以便 simplify-by-decoration decorate-refs=...工作。这些选项中的任何一个都可能意味着 decorate=short如果它当前仍然auto在Git配置中未设置。2

这一切都指向了以编程方式使用git log的一个更普遍的问题,例如,从Python使用subprocessgit log是Git所称的陶瓷命令,这意味着它遵守用户配置。如果用户具有log.decorate设置,则会覆盖任何默认设置。现在您已经了解了log.decorate decorate=参数,您可以使用 decorate=参数(覆盖任何用户配置)强制程序中的正确行为。但是git log中存在哪些其他用户可配置项可能会破坏您的程序?关于未来版本的Git,git log可能获得新配置项的Git呢?不幸的是,对于今天这个更普遍的问题,无能为力,但由于git log所做的某些事情无法通过任何所谓的管道命令来完成,因此这些命令不会根据用户配置改变行为,因此对于其他程序非常有用,因为它们具有已知的,固定输出格式-git log需要一个选项使其运行良好。(对于这个,git status命令有 porcelain选项;git log只需要它自己的版本。)


1Git实际上不知道人类是否在读取输出。相反,它通过检查标准输出流来近似这一点:如果标准输出(文件描述符1)为isattyC库调用响应一个真值,或者git log输出被馈送到寻呼机,则它假定有人正在读取输出。在subprocess中使用管道意味着stdout是而不是tty,这在默认情况下也会禁用寻呼机。但是,有一个用户配置设置强制使用寻呼机:请参阅“更一般的问题”一段

2一般来说,Git配置的工作方式如下:

  • 首先,程序设置任何自动默认值,例如log.decorate=auto(这通常是开放编码的,而不是使用配置机制)

  • 接下来,Git读取系统配置文件。如果其中有log.decorate=short之类的设置,则该设置将应用,覆盖自动默认设置。(这通常通过从配置机制到程序的回调来实现。)

  • 接下来,Git读取您的个人全局配置文件。如果其中有log.decorate=auto之类的设置,则该设置适用。如果以前的配置有设置,则会覆盖以前的设置

  • 接下来,Git读取这个特定Git存储库的配置文件。如果有log.decorate=full这样的设置,则应用该设置,覆盖以前的任何设置

  • 最后,Git应用命令行参数设置。因此,这些将覆盖在前面任何步骤中拾取的任何设置

例如,这就是如何为一个特定的Git存储库安排user.name和/或user.email不同的方式。您可以在全局配置中设置这些,哪个Git在读取每个存储库配置之前读取;然后在每个存储库配置中将它们设置为不同的值,这将覆盖全局配置

在相对较新版本的Git中,还可以为每个工作树配置设置一个git config worktree。这是在每个存储库配置文件之后读取的,但在命令行参数之前使用,因此它具有第二高的优先级。要使每工作树设置生效,必须启用extensions.worktreeConfig。这里要小心,因为这个扩展有一些bug

相关问题 更多 >