【问题标题】:Trailers option in git --pretty optiongit --pretty 选项中的 Trailers 选项
【发布时间】:2020-12-20 07:52:06
【问题描述】:

我试图从 git log 中提取贡献摘要并创建一个简明摘要,并从中创建一个 excel/csv 来呈现报告。

我试过

git log --after="2020-12-10" --pretty=format:'"%h","%an","%ae","%aD","%s","(trailers:key="Reviewed By")"'

CSV 看起来像末尾有一个空白的 CSV 列。

...
"7c87963cc","XYZ","xyz@abc.com","Tue Dec 8 17:40:13 2020 +0000","[TTI] Add support for target hook in compiler.", ""
...

git log 看起来像

commit 7c87963cc
Author: XYZ <xyz@abc.com>
Date:   Tue Dec 8 17:40:13 2020 +0000

    [TTI] Add support for target hook in compiler.

    This adds some code in the TabeleGen ...
    This is my body of commit.

    Reviewed By: Sushant

    Differential Revision: https://codereviews.com/DD8822

我无法成功的是使用(trailers:key="Reviewed By") 命令提取Differential Revision 字符串。

我找不到太多关于如何让它工作的信息。 我检查了 git 手册,我确实尝试了它的解释。

这个命令有什么我可能遗漏的吗? 预期的输出应该有文本 https://codereviews.com/DD8822 在上述 CVS 输出的最后一个位置。

【问题讨论】:

  • 您能否详细解释一下获取示例输出的逻辑部分以及您问题中的示例输出;让问题更清楚。
  • @RavinderSingh13 完成。
  • 我注意到你的trailers占位符开头没有%。

标签: linux git awk grep


【解决方案1】:

我不确定,但是:

  • 预告片键不能有空格(因此Reviewed By -> Reviewed-By,和Differential Revision -> Differential-Revision);
  • 预告片不应以新行分隔,而应与提交提交消息分开(因此您的问题中的Reviewed By 不被视为预告片)。

我也不推荐使用 CSV,而是使用 TSV:git 输出不知道 CSV 语法(分号和逗号转义),因此输出文档可能无法解析。

如果您的提交消息看起来像这样(- 而不是空格,没有换行符):

commit 7c87963cc
Author: XYZ <xyz@abc.com>
Date:   Tue Dec 8 17:40:13 2020 +0000

    [TTI] Add support for target hook in compiler.

    This adds some code in the TabeleGen ...
    This is my body of commit.

    Reviewed-By: Sushant
    Differential-Revision: https://codereviews.com/DD8822

那么下面的命令会为你工作:

git log --pretty=format:'%h%x09%an%x09%ae%x09%aD%x09%s%x09%(trailers:key=Reviewed-By,separator=%x20,valueonly)%x09%(trailers:key=Differential-Revision,separator=%x20,valueonly)'

为您的制表符分隔值输出生成简短的提交 ID、作者姓名、作者电子邮件、日期、提交消息、预告片 Reviewed-By 和预告片 Differential-Revision。


如果您不能更改旧的提交消息,因为您的历史记录不安全(它已发布,由同行拉取,您的工具绑定到已发布的提交哈希),那么您必须处理 git log 输出使用sed、awk、perl 或任何其他文本转换工具来生成您的报告。比如说,处理git log --pretty=format:'%x02%h%x1F%an%x1F%ae%x1F%aD%x1F%s%x1F%n%B' 之类的东西,其中应该以某种方式分析^B (STX) 和 EOF 之间的行(过滤您感兴趣的预告片),然后加入以^B 开头的组行,然后替换字符分别用\t 和无字符替换字段和条目分隔符。

但同样,如果您可以通过修复提交消息预告片来编辑历史记录(不确定它可能会影响多少),我建议您这样做,然后拒绝额外脚本处理 @ 无法识别的预告片的想法987654342@ 并简单地修复提交消息。


编辑 1(文本工具)

如果重写历史不是一个选项,那么实现一些脚本可能会对您有所帮助。我在编写强大的sed/awk/perl 脚本方面相当薄弱,但让我试试吧。

git log --pretty=format:'%x02%h%x1F%an%x1F%ae%x1F%aD%x1F%s%x1F%n%B' \
    | gawk -f trailers.awk \
    | sed '$!N;s/\n/\x1F/' \
    | sed 's/[\x02\x1E]//g' \
    | sed 's/\x1F/\x09/g'

它是如何工作的:

  • git 生成一个由标准 C0 C1 codes 分隔的数据组成的日志,假设您的提交消息(STX、RS 和 US)没有这样的字符——我真的不知道这是否是一个像这样使用它们的好地方,如果我在语义上正确应用它们);
  • gawk 过滤日志输出,试图解析 STX 开始的组并提取预告片,生成“两行”输出(每个奇数行用于常规数据,每个偶数行用于逗号连接的预告片值,即使对于丢失的预告片);
  • sed 成对加入奇偶行(致谢Karoly Horvath);
  • sed 移除 STX 和 RS;
  • sed 将 US 替换为 TAB。

这里是trailers.awk(同样,我不是awk 的人,不知道下面的脚本有多惯用,但它似乎可以工作):

#!/usr/bin/awk -f

BEGIN {
    FIRST = 1
    delete TRAILERS
}

function print_joined_array(array) {
    if ( !length(array) ) {
        return
    }
    for ( i in array ) {
        if ( i > 0 ) {
            printf(",")
        }
        printf("%s", array[i])
    }
    printf("\x1F")
}

function print_trailers() {
    if ( FIRST ) {
        FIRST = 0
        return
    }
    print_joined_array(TRAILERS["Reviewed By"])
    print_joined_array(TRAILERS["Differential Revision"])
    print ""
}

/^\x02/ {
    print_trailers()
    print $0
    delete TRAILERS
}

match($0, /^([-_ A-Za-z0-9]+):\s+(.*)\s*/, M) {
    TRAILERS[M[1]][length(TRAILERS[M[1]])] = M[2]
}

END {
    print_trailers()
}

简单说一下awk 脚本的工作原理:

  • 假定不需要处理的记录以 STX 开头;
  • 它尝试grep 每个非“STX”行以获取Key Name: Value 模式并将找到的结果保存到临时数组TRAILERS(实际上用作多映射,如Java 中的Map&lt;String, List&lt;String&gt;&gt;)每条记录;
  • 每条记录都按原样写入,但预告片会在检测到新记录之前或在 EOF 处写入。

编辑2(更好awk)

好吧,我在awk 方面真的很弱,所以一旦我阅读了更多关于awk 内部变量的信息,我发现awk 脚本可以完全重新实现,并产生一个准备好使用的类似TSV 的输出本身无需使用sed 或perl 进行任何后期处理。所以脚本的更短和改进的版本是:

#!/bin/bash

git log --pretty=format:'%x1E%h%x1F%an%x1F%ae%x1F%aD%x1F%s%x1F%B%x1E' \
    | gawk -f trailers.awk
#!/usr/bin/awk -f

BEGIN {
    RS = "\x1E"
    FS = "\x1F"
    OFS = "\x09"
}

function extract(array, trailer_key, __buffer) {
    for ( i in array ) {
        if ( index(array[i], trailer_key) > 0 ) {
            if ( length(__buffer) > 0 ) {
                __buffer = __buffer ","
            }
            __buffer = __buffer substr(array[i], length(trailer_key))
        }
    }
    return __buffer
}

NF > 1 {
    split($6, array, "\n")
    print $1, $2, $3, $4, $5, extract(array, "Reviewed By: "), extract(array, "Differential Revision: ")
}

更简洁,更易于阅读、理解和维护。

【讨论】:

  • 另外值得一提的是:Git 目前正在进行大量工作来加强预告片的处理。我不认为这允许空间,但我不确定,因为我没有注意它。
  • 感谢@fluffy 的详细回答。好吧,不可能更改提交日志。因此,首先使用 awk 其他工具的方式似乎很难。顺便说一句,我确实尝试了 awk 方法,而不是您提到的方法,但我想到了一些技巧,我可以根据需要从提交消息中收集所有字段(它基本上基于 --author 过滤 git log)但是当有情况时问题就来了当提交日志的消息正文中不存在“审阅者”时。这成为 CSV/TSV 中的错误案例。有没有办法分解每个提交消息(其中的所有字段)并保存在列表或其他东西中?
  • 基本上我想做的是``` 1.获取git日志。 2. 搜索特定作者的提交。 3.从中提取一些特定的字段。 4. 以一些基于 CVS/TSV 的格式保存(最终目标是创建一个 excel) 5. 导入一个 excel。 6. 从中创建一些图表。 ``` 只是提到是否有更好的、不同的和简单的方法来解决这个众所周知的问题。也许我可能错过了传达一些东西..
  • @fluffy 我能想到的另一种方法是。如果 git 将 git 日志数据保存在我本地机器上的某个位置。我可以将它的副本创建到一个单独的文件(tempfile.txt)中并按照提到的那样更改关键字,然后使用可以输入(tempfile.txt)的格式化命令。听起来怎么样,有可能吗?
  • 感谢指点。我有一个基本的工作版本,它帮助我们获得了更好的见解。 github.com/Sameeranjoshi/git-log-stats
猜你喜欢
  • 1970-01-01
  • 2021-03-31
  • 2013-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-07
  • 2016-07-01
  • 1970-01-01
相关资源
最近更新 更多