在列工具中,`wrapnl` 列属性是如何工作的?

编程语言 2026-07-07

我想用 git log --pretty=formatcolumn 的组合来生成一个表格。理想的输出大致像是:

Age                   Commit Message                                Author

21 hours ago          Update to 3.14.15                             Speedy

                      I made these changes, blah blah blah

1 year, 5 months ago  Fix this issue X                              Speedy

                      Other info
                      Link to something

3 years ago           Make a really big change to the code          Speedy

                      Cue a long list of things that were changed.
                      - foo
                      - bar
                      - baz

然而,最接近我现在能做到的则是:

Age                                   Commit Message  Author

21 hours ago                          Update to 3.14.15

I made these changes, blah blah blah

                                      Speedy

1 year, 5 months ago                  Fix this issue X

Other info
Link to something

                                      Speedy

3 years ago                           Make a really big change to the code

Cue a long list of things that were changed.
- foo
- bar
- baz

                                      Speedy

经过一些变体(因为我已经尝试解决这个问题有一段时间了),我的获取提交的命令是

commits="$(git log --pretty=format:$'%cr\t%s\n%b\t%an')"

而我的表格打印命令是

column -t -s$'\t' -E2 -C'name=Age' -C'name=Commit Message,wrapnl' -C'name=Author,right' <<<"$commits"

我尝试过的一些方法:

  • git-log 的输出通过管道送入 tr '\n' '\r',在 column 下设置 --wrap-separator $'\r'
  • 所有内容都在一个单元格中,因为每个列表项的换行也被回车符(CR)所替代
  • --pretty:format 追加 '\x00',将 git-log 的输出通过管道送入 tr '\n' '\r' | sed 's/\x00\r/\n/g',并为 column 设置 --wrap-separator $'\r'
  • 与前一点的结果相同,可能是因为 tr 消除了空字符
  • 将前两点的做法结合起来,但把 column 下的 wrapnl 替换为 wrap
  • 与之前相同的结果
  • 使用 column 的各自独立的 --table-* 选项
  • 与之前相同的结果

写到这里,我想接下来尝试将每条提交的信息单独追加到一个bash数组中,方法是遍历 git log --pretty=format:'%H' 的结果(返回提交哈希值)。这样,我就能更容易地控制每一项的控制字符。

解决方案

正如预期,我通过遍历哈希列表解决了这个问题——这可能并不理想,因为每个哈希都需要重新调用 git。 (编辑:) 对于大型仓库来说会花很长时间——这台笔记本最高时钟频率只有1 GHz,在Arch Linux linux 软件包的日志上大约花了13秒(因此我放弃了这个梦想。不过,若再多加改动,还是有可能实现的)。

# Get list of commit hashes
hashes="$(git log --pretty=tformat:'%H')"
if [ "${#hashes}" -eq 0 ]; then
  echo 'ERROR: No commits found' >&2
  exit 1
fi

# Get array of commit info
declare -a commits
while read -r hash; do
  commits+=("$(git show --no-patch --pretty=format:"$gitformat" "$hash" | tr '\n' '\r' | sed 's/\r/\n\t/g')")  # `tr` is needed here because `sed` works line-by-line
done <<<"$hashes"

# Print data
column --table --separator $'\t' --keep-empty-lines -C'name=Age' -C'name=Commit Message,noextreme,wrap' -C'name=Author,right' <(printf '%s\n' "${commits[@]}")

git log 步骤中,使用 --pretty=tformat 而非 --pretty:format 十分重要,因为如果没有跟随前者提供的尾随换行符,read 将跳过最后一个条目。

有趣的部分(git show ...)通过把提交信息中的换行符转换成回车符来实现——这并非完全安全,但我觉得出现其中一个这种字符的概率很低——随后使用 sed 把回车符转换成换行符再跟一个制表符。制表符用来把行推到第二列,因此若列数增多,可能需要更多的制表符。之所以要先把换行符改为中间字符,是因为 sed 是按行处理的;否则,我觉得这相当于无操作。

最后,是打印阶段。这里唯一可能让人困惑的部分是 --keep-empty-lines 标志。它的作用是在每条条目之间保留一个空行,便于阅读。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章