【问题标题】:Handling expanded git commands with python subprocess module使用 python 子进程模块处理扩展的 git 命令
【发布时间】:2019-01-03 10:39:47
【问题描述】:

我正在尝试从 git 存储库中的文件的历史版本中检索和处理数据。我想要一个字典之类的东西,其中包含每个条目的<hash>, <time of commit>, <value retrieved from contents of a file revision>, <commit message>

我认为我从每个文件修订中检索到的数据以及使用它们完成的任何计算都最好使用 python 处理。 subprocess 模块似乎最适合集成我的 git 命令。

下面我展示了我如何定义一个函数 getval(key, filename),我希望将 <SHA-1 hash>:<Value> 输出到控制台,但希望有一个包含更多信息的 dict... 还有 <time> 和 @987654325 @。

我帮助操作离子加速器,我们使用 git 在其中存储“保存集”——或与给定加速器调谐相关的值。这些文件中的值包括电荷(Q)和质量(A)。最终,我想检索这两个值,获取比率 (Q/A),并显示一个文件修订哈希列表,按我们提供的离子的电荷:质量比排序,以及该文件修订中的设置。

文件样本(56Fe17+):

# Date: 2018-12-21 01:49:16.888 PV,SELECTED,TIMESTAMP,STATUS,SEVERITY,VALUE_TYPE,VALUE,READBACK,READBACK_VALUE,DELTA,READ_ONLY REA_EXP:LINE,0,1544047322.881066957,NO_ALARM,NONE,enum,"JENSA~[UDF;AT-TPC;GPL;JENSA]",,"---",,true REA_BTS19:BEAM:OPTICSFILE,0,1541798820.065952460,NO_ALARM,NONE,string,"BTS19_test3.data",,"---",,true REA_BTS19:BEAM:A_BOOK,0,1545322510.562031883,NO_ALARM,NONE,double,"56.0",,"---",,true REA_BTS19:BEAM:Z_BOOK,0,1545322567.544226340,NO_ALARM,NONE,double,"26.0",,"---",,true REA_BTS19:BEAM:Q_BOOK,0,1545322512.701768974,NO_ALARM,NONE,double,"17.0",,"---",,true

到目前为止——在其他人的帮助下——我已经找到了一个 git one-liner,它可以 greps 给定文件的修订历史以获取键 [a string] 并使用 sed 和 awk 输出 @ 987654327@.

我开始使用 Git Oneliner:

git grep 'BTS19:BEAM:A_BOOK' $(git rev-list --all) -- ReAccelerator/Snapshots/RFQ-JENSA_Setpoints.snp | sed 's/:/,/' | awk -F, '{print $1 ":" $8}'

Oneliner 的输出

e78f73fe6f90e93d5b3ccf90975b0e540d12ce09:"56.0" 4b94745bd0a6594bb42a774c95b5fc0847ef2d82:"56.0" f2d5e263deac1d9112be791b39f4ce1b1b34e55d:"56.0" c03800de52143ddb2abfab51fcc665ff5470e363:"56.0" 4a3a564a6d87bc6ff5f3dc7fec7670aeecfe6a79:"58.0" d591941e51c4eab1237ce726a2a49448114b8f26:"58.0" a9c8f5cdf224ff4fd94514c33888796760afd792:"58.0" 2f221492beea1663216dcfb27da89343817b11fd:"58.0"

我也开始使用 subprocess python 模块。但我正在努力弄清楚如何处理我更复杂的 git 命令。一般来说,我希望能够传递一个密钥和一个文件......类似于getval(key, filename)

当我的 cmd 字符串是 ['git', 'grep', str, '$(git rev-list --all)', '--', pathspec] 时,它返回错误,指出 '$(git rev -list --all)' 模棱两可。认为它没有被扩展,我添加了一个单独的进程来执行嵌套命令,但我不确定我这样做是否正确。

我的 Python 文件 (gitfun.py):我目前正在从中运行函数

import sys, os
import subprocess

def getval(str, pathspec, repoDir='/mnt/d/stash.projects/rea'):
    p1 = subprocess.Popen(["git", "rev-list", "--all"], stdout=subprocess.PIPE)
    output, err = p1.communicate()

    cmd = ['git', 'grep', str, output, '--', pathspec]        
    p2 = subprocess.Popen(cmd, cwd=repoDir)
    p2.wait()

cwd = '/mnt/d/stash.projects/rea'
filename = 'ReAccelerator/Snapshots/RFQ-JENSA_Setpoints.snp'
os.chdir(cwd)
getval('BTS19:BEAM:A_BOOK', filename)

目前它正在返回 'file name too long' 所以(即使我不相信它真的太长了)我尝试将 git config 中的 core.longpaths 更改为 true,但这没有效果。再次说明为什么我怀疑我没有正确处理 $(git rev-list --all) 扩展的替换。

对于 this 代码,我希望看起来像这样:

522628b8d3db01ac330240b28935933b0448649c:ReAccelerator/Snapshots/RFQ-JENSA_Setpoints.snp:REA_BTS19:BEAM:A_BOOK,0,1545240215.74320185 5,NO_ALARM,NONE,double,"58.0",,"---",,true 2557c599d2dc67d80ffc5b9be3f79899e0c15a10:ReAccelerator/Snapshots/RFQ-JENSA_Setpoints.snp:REA_BTS19:BEAM:A_BOOK,0,1545240215.74320185 5,NO_ALARM,NONE,double,"58.0",,"---",,true 7fc97ec2aa76f32265196c42dbcd289c49f0ad93:ReAccelerator/Snapshots/RFQ-JENSA_Setpoints.snp:REA_BTS19:BEAM:A_BOOK,0,1545240215.74320185 5,NO_ALARM,NONE,double,"58.0",,"---",,true ...

但我最终希望控制台的输出看起来与上面的 git one-liner 相同,或者更好的是,我可以打印到控制台或做其他事情的 dict。

【问题讨论】:

    标签: python-3.x git subprocess


    【解决方案1】:

    请记住,您的 shell 使用空格标记命令行。

    当你运行 git rev-list --all 时,你会得到如下输出:

    2a4be2748fad885f88163a5b9b1b438fe3cb2ece
    c1a30c743eb810fbefe1dc314277931fa33842b3
    b2e5c75131e94a3543e5dcf9fb641ccd553906b4
    95718f7e128a8b36ca93d6589328cc5b739668b1
    87a9ada188a8cd1c13e48c21f093be7027d61eca
    

    当您将其替换为您的 git grep 命令时...

    git grep 'BTS19:BEAM:A_BOOK' $(git rev-list --all) -- \
    ReAccelerator/Snapshots/RFQ-JENSA_Setpoints.snp
    

    ...每一行都是一个单独的参数。也就是说,如果 git rev-list --all 的输出正是我上面显示的,那么你的单行将被标记为以下参数,为了清楚起见,我每行列出一个:

    git
    grep
    BTS19:BEAM:A_BOOK
    2a4be2748fad885f88163a5b9b1b438fe3cb2ece
    c1a30c743eb810fbefe1dc314277931fa33842b3
    b2e5c75131e94a3543e5dcf9fb641ccd553906b4
    95718f7e128a8b36ca93d6589328cc5b739668b1
    87a9ada188a8cd1c13e48c21f093be7027d61eca
    --
    ReAccelerator/Snapshots/RFQ-JENSA_Setpoints.snp
    

    但是您没有在 Python 代码中执行此操作!您将 git rev-list --all 的整个输出作为 single 参数进行传递。这意味着您尝试执行的命令具有固定数量 (6) 的参数:

    git
    grep
    BTS19:BEAM:A_BOOK
    2a4be2748fad885f88163a5b9b1b438fe3cb2ece c1a30c743eb810fbefe1dc314277931fa33842b3 b2e5c75131e94a3543e5dcf9fb641ccd553906b4 95718f7e128a8b36ca93d6589328cc5b739668b1 87a9ada188a8cd1c13e48c21f093be7027d61eca
    --
    ReAccelerator/Snapshots/RFQ-JENSA_Setpoints.snp
    

    所有这些修订都捆绑在一个参数中,这就是“文件名太长”错误的来源。您需要像 shell 一样将该输出拆分为多个参数:

    p1 = subprocess.Popen(["git", "rev-list", "--all"], stdout=subprocess.PIPE)
    output, err = p1.communicate()
    
    cmd = ['git', 'grep', str] + output.splitlines() + ['--', pathspec]        
    p2 = subprocess.Popen(cmd, cwd=repoDir)
    p2.wait()
    

    【讨论】:

    • 旁注:如果你想像外壳一样拆分,shlex.split 会更接近。在这种情况下,输出确实是行,所以output.splitlines() 当然可以。 (此外,标签中提到了 Python 3.x,因此请注意子进程输出默认为字节,而不是字符串。)
    • 啊哈!谢谢你们俩!这个很有趣。 @larsks, output.splitlines() 使这项工作按预期进行。 @Torek标签没有错,我使用的是python 3。一旦我怀疑输出是一个问题,我就探测了类型(输出),它确实是字节。我不太确定这意味着什么......事实证明, output.splitlines() 与 bytes 类型一起使用,但 shlex.split 没有。 shlex.split 返回Attribute Error: 'bytes' object has no attribute 'read'
    • 另外,在应得的地方给予赞扬,如果有人觉得这很有用,请为我的问题提供一些连续性。 @Torek 是帮助我弄清楚我的单线的人。 stackoverflow.com/questions/53951431/…。再次感谢!
    • @DanielCrisp:在 Py3k 中处理混合的 bytesstr 很痛苦。这里要记住的技巧是外部程序(git 和其他由subprocess 运行的东西)确实可以处理 byte 流;如果你想要字符,它们往往是 UTF-8 编码的,这样你就可以拼写“agréable”之类的,其中 é 和 ö 等等占用超过一个字节。 Py3k str 字符每个都是一个 Unicode 点。
    • @torek:在这一点上......我已经开始尝试以与 p1 相同的方式捕获 p2 的输出。但我也想把它打印出来。问题是 print(output2) 没有将 \n 的出现转换为实际的新行。所以我试图处理编码......但这些都不起作用:print(output.decode('utf-8')),然后是print(output.format(output.decode('utf-8')), end=''),和print(str(output, 'utf-8'))。 [ETC。来自stackoverflow.com/questions/606191/convert-bytes-to-a-string]。您还有什么建议吗?
    猜你喜欢
    • 2012-09-05
    • 2011-10-30
    • 2013-07-30
    • 1970-01-01
    • 1970-01-01
    • 2010-12-17
    • 1970-01-01
    • 2016-10-12
    • 1970-01-01
    相关资源
    最近更新 更多