git describe --always 仍输出标签,无法得到纯提交哈希
git describe 的 --always 只提供无合适名称时的哈希回退。有标签时改用 rev-parse 获取提交 ID;需要 dirty 标记时明确排除标签,并核对下游版本格式。
构建脚本原来用 git describe --always 生成版本标识,换一个有标签的仓库后,输出从短哈希变成了标签或带标签的长描述。若后续代码只接受哈希,版本解析就可能失败。
--always 的含义是没有合适名称时退回缩写提交 ID,并不是无条件只输出提交 ID。仓库中有可用标签时,describe 仍会优先按自己的规则生成描述。
本文处理已经存在提交的 Git 仓库,以及构建脚本对输出格式的要求。示例使用当前 Git 文档中的选项;较旧版本若不识别 --exclude,可先采用只取提交 ID 的方案,不要把选项错误当成仓库损坏。
只需要提交 ID,改用 rev-parse
如果版本文件需要的是当前提交的完整 ID,直接验证并读取 HEAD:
git rev-parse --verify 'HEAD^{commit}'
^{commit} 要求目标可以解析为提交对象。空仓库尚无第一次提交时,这条命令会失败;应由构建流程处理这种输入条件,不要将错误输出写成版本号。
需要短 ID 时可以使用:
git rev-parse --short=12 HEAD
12 是要求的最小缩写长度,不是任何仓库里都固定输出 12 个字符的保证。Git 可能增加字符以消除歧义。用于长期审计、准确追踪构建提交的字段,保留完整 ID 更直接;用于界面显示的短值可以另存。
这两条命令不依赖标签名称,也不会因为新增标签而把输出变成标签。它们只标识提交,不反映工作区中尚未提交的改动。
需要 dirty 标记时,显式排除标签候选
如果仍希望由 describe 附加工作区修改标记,可以同时排除所有标签候选,并保留缩写 ID 的回退:
git describe --always --dirty --abbrev=12 --exclude '*'
--exclude '*' 排除名称匹配该 glob 模式的标签;没有可用标签后,--always 才退回提交缩写。--dirty 在检测到本地修改时附加 -dirty。因此,这个方案得到的是“短 ID 加可选标记”,不是始终仅含十六进制字符的字符串。
星号必须保持为传给 Git 的单个参数。上面的单引号防止 shell 先把它展开成当前目录里的文件名。不要省略引号后再通过调整当前目录来掩盖输出差异。
也不要为了只显示哈希而删除本地或远端标签。标签可能被发布流程、依赖解析或其他开发者使用;改变 describe 的候选过滤条件就足够,不需要改仓库引用。
--tags、--all 和 --long 都不是“只取哈希”
默认的 describe 只考虑带注释标签。--tags 扩大到包括轻量标签;--all 还会考虑分支等引用。这些选项都没有关闭名称描述。
--long 强制长格式,即使提交恰好被标签直接指向,也保留“标签、提交数、缩写 ID”的组合。它不会移除标签前缀。若目标是避免名称影响机器解析,不能只是在原命令后追加 --long。
不要从 describe 输出中按固定数量的连字符切割出哈希。标签名本身可能含连字符,而且精确命中标签时,默认输出可能没有哈希后缀。根据需要直接选用 rev-parse,或采用明确过滤名称的 describe 命令。
将命令失败与版本字符串分开处理
在 Bash 构建脚本里,可以先检查读取是否成功,再输出版本字段:
#!/usr/bin/env bash
if revision=$(git rev-parse --verify 'HEAD^{commit}'); then
printf 'revision=%s\n' "$revision"
else
printf '%s\n' 'Cannot resolve HEAD to a commit' >&2
exit 1
fi
这段示例只打印结果。接入实际版本文件之前,确认脚本是在预期仓库中运行,且没有把标准错误重定向进版本变量。无 Git 元数据的源码压缩包、没有提交的仓库、读取对象失败,都需要自己的构建策略,--always 不能包办这些情况。
若采用带 dirty 后缀的方案,下游解析器应明确允许该后缀。也不要把 dirty 状态当成源代码快照:它不能告诉你具体改了什么,也不能让未提交的内容凭提交 ID 重现。可复现发布仍需要明确保存实际参与构建的源码状态。
用同一提交核对格式,再恢复发布流程
先在只读取仓库的检查步骤中并列查看完整 ID 和所选显示格式,确认短 ID 是该提交的前缀。对于已有标签的 HEAD,采用排除标签的方案后,不应再出现标签前缀;对于无可用标签的提交,也应能返回提交缩写。
如果流程使用 dirty 标记,分别在已有的干净工作区和包含已知修改的测试工作区核对后缀,再检查版本文件、安装包元数据或构建日志的解析结果。不要为了测试标记,在发布工作区随意改文件或创建临时标签。
修改前保存旧的版本生成配置。若消费者尚未兼容新的格式,回退该配置并重新生成构建产物。配置回退不会更改已经发布的包内版本字段,因此应先验证本地构建输出,再接入正式发布任务。


