格式字符串,用于在 `git log --pretty` 输出的条目之间进行一致分隔

Format string for consistent separation between entries output by `git log --pretty`

我正在尝试开发一个格式字符串以传递给 git log --pretty 以便每个日志条目都以完整的提交消息结尾,但每个日志条目由 正好一个 空行。问题是一些完整的提交消息以换行符结尾,而另一些则没有。

例如,假设我有两个提交,abc1234def5678,但只有 abc1234 在完整提交消息的末尾包含换行符。在命令行上输出原始提交内容看起来像这样:

[prompt]$ git cat-file commit abc1234
(...)

Title FOO

Full commit message FOO
[prompt]$ git cat-file commit def5678
(...)

Title BAR

Full commit message BAR[prompt]$

注意新的 shell 提示如何出现在最后一行输出的末尾,表明提交 def5678 包含换行符完整提交消息的结尾。

假设 def5678abc1234 的 parent,我想输出一个简单的日志,其中每个条目仅包含短提交哈希、标题行和完整提交信息。我可能会尝试这样的事情:

[prompt]$ git log --graph --pretty='commit %h%n%B' abc1234
* commit abc1234
| Title FOO
| 
| Full commit message FOO
|
* commit def5678
| Title BAR
|
| Full commit message BAR
* commit <parent of def5678>
(...)

注意日志条目之间的间距。 abc1234def5678 的条目由空行分隔(图形字符除外),但 def5678 及其 parent 的条目不是。

如何构建格式字符串,使间距保持一致,即使完整提交消息的终止不一致? mediumfullfulleremail 的内置漂亮格式已经做到了这一点,但我希望能够构造任意格式字符串来做同样的事情。

我已经尝试过 %+B%-B% B 序列(以及它们的 %b%n 等价物),但我只能' 似乎得到了一致的间距。

我正在使用 Git 2.17.0,如果有区别的话。

来自 git log 手册页:

-z

Separate the commits with NULs instead of with new newlines.

有了它,您就可以清楚地分离每条消息。然后,对于每个 留言,add a line terminator in the end only if it is missing one.

示例:

fix-eol:

#!/bin/sh

lastchar="$(printf -- '%s\n' "$@" | tail -c1 | od -An -tx1)"

# output the input as is
printf -- '%s' "$@"

# print a newline only if it's missing
test "$lastchar" = ' 0a' && printf -- '\n'

用法:

git log -z --pretty='commit %h%n%B' | xargs -0 -n1 ./fix-eol

注意::我无法保存缺少行终止符的提交消息 (似乎 git 自动修复了它们),但是脚本在这样的情况下工作 文件。此外,根据消息的大小和内容,问题可能 出现,因为每条消息都作为参数传递(即:这是一个快速的 hack)。

P.S.:可能可以改进示例以避免使用 单独的脚本。

正如@jthill 在评论中提到的,并在 git-log(1) 中表达:

If you add a - (minus sign) after % of a placeholder, all consecutive line-feeds immediately preceding the expansion are deleted if and only if the placeholder expands to an empty string.

因此,如果我们能找到一个总是扩展为空字符串的格式序列%<token>,我们可以使用%-<token>%n替换零或使用单个换行符的更多连续换行符。原来,有这样一个格式序列:%C(),空颜色选择器。 (通常括号中包含一个非空字符串,指定要在日志输出中使用的颜色。有关详细信息,请参阅 git-log(1)git-config(1)。)

%C() 计算为空字符串而不是导致错误的事实似乎是一个快乐的意外而不是值得一提的事情,但至少对于 Git 2.17,它确实如此诀窍。在这一点上,我有足够的信息来回答我自己的问题。

为了保持 git log --pretty=<tformat> 输出的日志条目之间的一致分隔,其中 <tformat> 可能会或可能不会评估为以换行符结尾的字符串,附加 %-C()%n<tformat>. 例如:

[prompt]$ git log --graph --pretty='commit %h%n%B%-C()%n' abc1234
* commit abc1234
| Title FOO
| 
| Full commit message FOO
|
* commit def5678
| Title BAR
|
| Full commit message BAR
|
* commit <parent of def5678>
(...)