You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

单条Git提交时Bash脚本while循环失效问题排查

单条提交时Bash脚本无法添加前缀的问题解决

问题重现

你编写的Bash脚本用于生成变更日志,逻辑是获取上一个符合tag_prefix*规则的标签之后的所有非合并提交,给每条提交消息添加- 前缀。当存在多条提交时输出符合预期,但仅单条提交时,脚本输出为空,预期应该是- commit_message_1。

脚本代码:

#!/bin/bash

tag_commits_reversed=$(git rev-list --tags --max-count=1)
tags=$(git describe --match "tag_prefix*" --abbrev=0 --tags $tag_commits_reversed)
commit_messages=$(git log $tags..@ --no-merges --pretty=format:"%s" -- . | while read line; do echo "- $line"; done)

echo $commit_messages

问题原因

核心问题出在read命令的行为和git log的输出格式上:

  1. read的行结束规则:read默认以换行符作为行的结束标记,当git log仅输出单条提交消息时,--pretty=format:"%s"的结果没有尾随换行符。此时管道输入的内容没有换行,read在读取时会因为没有遇到换行标记,在管道关闭时返回非零退出状态,导致while循环根本不会执行,自然没有输出。
  2. 另外,echo $commit_messages的写法会把变量中的换行符替换为空格,多条提交时看似正常,实则破坏了每行独立的结构,应该改为echo "$commit_messages"来保留换行。

解决方案

有两种简洁的修复方式:

方式一:修复read的循环逻辑

给read添加-r参数(避免反斜杠被转义),同时在循环条件中加入|| [[ -n $line ]],确保即使最后一行没有换行符,只要内容非空就会处理:

#!/bin/bash

tag_commits_reversed=$(git rev-list --tags --max-count=1)
tags=$(git describe --match "tag_prefix*" --abbrev=0 --tags $tag_commits_reversed)
commit_messages=$(git log $tags..@ --no-merges --pretty=format:"%s" -- . | while read -r line || [[ -n $line ]]; do echo "- $line"; done)

# 加双引号保留换行格式
echo "$commit_messages"

方式二:直接用git log生成带前缀的输出

完全不需要管道和循环,直接在git log的--pretty=format中指定前缀,这是更高效且可靠的方式:

#!/bin/bash

tag_commits_reversed=$(git rev-list --tags --max-count=1)
tags=$(git describe --match "tag_prefix*" --abbrev=0 --tags $tag_commits_reversed)
# 直接在format中加入"- "前缀
commit_messages=$(git log $tags..@ --no-merges --pretty=format:"- %s" -- .)

echo "$commit_messages"

这个方式从根源避免了管道和read的兼容性问题,不管是单条还是多条提交,都能正确生成带前缀的每行消息。

内容的提问来源于stack exchange,提问作者ProtocolGuy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 01:01:24