git_tag_list
Git 标签 美化列表
一键脚本
bash <(curl -sL gitee.com/meimolihan/cmdbox/raw/master/sh/git_tag_list.sh) 5 /vol1/1000/GitHub/cmdbox-main
bash <(curl -sL ../sh/git_tag_list.sh) 5 /vol1/1000/GitHub/cmdbox-main
| 传参方式 | 命令示例 | 说明 |
|---|---|---|
| 不传参 | 脚本.sh | 默认显示当前目录最近 3 个标签 |
| 指定数量 | 脚本.sh 5 | 显示最近 5 个标签 |
| 指定目录 | 脚本.sh /path/to/repo | 显示指定 Git 仓库的标签 |
| 数量+目录 | 脚本.sh 5 /path/to/repo | 指定显示 5 个标签来自指定目录 |
| 目录+数量 | 脚本.sh /path/to/repo 5 | 参数顺序可互换 |
补充说明
该脚本提供 Git 标签信息的美化展示功能,默认显示最近 3 个标签的详细信息(含创建人、创建时间、绑定提交哈希、提交作者、提交说明),将英文星期和月份翻译为中文,以表格形式分栏对齐输出。支持指定显示数量和目标仓库目录。
效果预览
功能特点
- 传参灵活:支持指定标签数量(数字)和/或目标仓库目录(路径),参数顺序可互换
- 项目名称显示:自动显示当前仓库目录名称
- 智能排序:按版本号倒序排列(
sort -t'v' -k2 -nr),默认取前 3 个标签 - 详细信息:显示标签创建人、创建时间、标签备注、绑定提交哈希、提交作者、提交说明
- 中文翻译:自动将英文星期(Mon/Tue...)和月份(Jan/Feb...)翻译为中文
- 表格对齐:自动检测
column命令实现分栏对齐 - 提交信息优化:自动将英文 "update" 替换为中文 "更新"
- 目录还原:执行结束后自动
cd回原始工作目录
注意事项
- 默认仅显示最近的 3 个标签,可通过传参自定义数量
- 指定目录时会自动
cd进入,执行完毕自动返回原目录 - 仅支持附注标签(annotated tag),轻量标签(lightweight tag)无 Tagger/Date 信息
- 需在 Git 仓库目录或通过参数指定 Git 仓库目录
脚本源码
#!/bin/bash
set -uo pipefail
list_color_init() {
export gl_hui=$'\033[38;5;59m'
export gl_hong=$'\033[38;5;9m'
export gl_lv=$'\033[38;5;10m'
export gl_huang=$'\033[38;5;11m'
export gl_lan=$'\033[38;5;32m'
export gl_bai=$'\033[38;5;15m'
export gl_zi=$'\033[38;5;13m'
export gl_bufan=$'\033[38;5;14m'
export reset=$'\033[0m'
}
list_color_init
break_end() {
echo -e "${gl_lv}操作完成${gl_bai}"
echo -e "${gl_bai}按任意键继续 ${gl_hong}.${gl_huang}.${gl_lv}.${gl_bai}\c"
read -r -n 1 -s -r -p ""
echo ""
clear
}
column_if_available() {
if command -v column &> /dev/null; then
column -t -s $'\t'
else
cat
fi
}
print_single_tag() {
local tag="$1"
echo -e ""
echo -e "${gl_huang}>>>【Git标签】${gl_lv}${tag}${gl_bai}"
echo -e "${gl_bufan}————————————————————————————————————————————————${gl_bai}"
local full_raw
full_raw=$(git show "${tag}" 2>/dev/null | sed '/^diff --git/Q')
if [[ -z "${full_raw}" ]]; then
printf "%s%s\t%s%s\n" "$gl_huang" "提示" "$gl_huang" "标签 ${tag} 读取失败" "$reset" | column_if_available
return 0
fi
echo "${full_raw}" | sed '/^tag '"${tag}"'/d' | awk -v key_color="$gl_lan" -v val_color="$gl_bufan" -v reset="$reset" '
BEGIN {
FS=": "; OFS="\t"
map_key["Tagger"] = "标签创建人"
map_key["Date"] = "标签创建时间"
map_key["commit"] = "绑定提交哈希"
map_key["Author"] = "提交作者"
map_week["Mon"]="周一"; map_week["Tue"]="周二"; map_week["Wed"]="周三"
map_week["Thu"]="周四"; map_week["Fri"]="周五"; map_week["Sat"]="周六"; map_week["Sun"]="周日"
map_month["Jan"]="01月"; map_month["Feb"]="02月"; map_month["Mar"]="03月"; map_month["Apr"]="04月"
map_month["May"]="05月"; map_month["Jun"]="06月"; map_month["Jul"]="07月"; map_month["Aug"]="08月"
map_month["Sep"]="09月"; map_month["Oct"]="10月"; map_month["Nov"]="11月"; map_month["Dec"]="12月"
state = "tag_info"
desc_flag = 0
msg_flag = 0
}
/^commit [0-9a-f]+/ {
sub(/^commit /,"",$0)
print key_color "绑定提交哈希" reset, val_color $0 reset
state = "commit_info"
next
}
state=="tag_info" && /^Tagger/ {
print key_color map_key["Tagger"] reset, val_color $2 reset
desc_flag=0
next
}
state=="tag_info" && /^Date/ {
raw_dt = $2
split(raw_dt, dt, " ")
w=dt[1]; m=dt[2]; day=dt[3]; time=dt[4]; year=dt[5]; zone=dt[6]
cn_week = w in map_week ? map_week[w] : w
cn_month = m in map_month ? map_month[m] : m
cn_dt = year "年" cn_month day "日 " time " " cn_week " " zone
print key_color map_key["Date"] reset, val_color cn_dt reset
desc_flag=0
next
}
state=="tag_info" && NF>0 && !/^[A-Za-z]+: / {
gsub(/^[ \t]+/,"",$0)
if (desc_flag == 0) {
print key_color "标签备注" reset, val_color $0 reset
desc_flag=1
} else {
print key_color "" reset, val_color $0 reset
}
next
}
state=="commit_info" && /^Author/ {
print key_color map_key["Author"] reset, val_color $2 reset
msg_flag=0
next
}
state=="commit_info" && /^Date/ { next }
state=="commit_info" && NF>0 {
gsub(/^[ \t]+/,"",$0)
gsub(/update/,"更新",$0)
if (msg_flag == 0) {
print key_color "提交说明" reset, val_color $0 reset
msg_flag=1
} else {
print key_color "" reset, val_color $0 reset
}
next
}
' | column_if_available
}
list_all_full_tags() {
local show_count=3
local target_dir="$PWD"
for arg in "$@"; do
if [[ "$arg" =~ ^[0-9]+$ ]]; then
show_count="$arg"
else
target_dir=$(realpath "$arg")
fi
done
local origin_pwd="$PWD"
if ! cd "$target_dir"; then
echo -e "${gl_hong}错误:目录 ${target_dir} 不存在或无法进入!${gl_bai}"
break_end
return 1
fi
clear
if ! git rev-parse --is-inside-work-tree &>/dev/null; then
echo -e "${gl_hong}当前目录「${target_dir}」不是Git仓库!${gl_bai}"
cd "$origin_pwd"
break_end
return 0
fi
local tag_list
tag_list=$(git tag 2>/dev/null | sort -t'v' -k2 -nr | head -n"${show_count}")
local current_dir_name
current_dir_name=$(basename "$PWD")
if [[ -z "${tag_list}" ]]; then
echo -e ""
echo -e "${gl_zi}【Git标签】${gl_lv}无${gl_bai}"
echo -e "${gl_bufan}————————————————————————————————————————————————${gl_bai}"
echo -e "${gl_hong}错误:仓库 ${current_dir_name} 不存在任何Git标签${gl_bai}"
echo -e "${gl_bufan}————————————————————————————————————————————————${gl_bai}"
cd "$origin_pwd"
break_end
return 0
fi
echo -e "${gl_zi}>>> ${gl_huang}${current_dir_name} ${gl_zi}项目 ${gl_huang}Git ${gl_zi}标签(展示前 ${gl_lv}${show_count} ${gl_zi}个) ${gl_bai}"
echo -e "${gl_bufan}————————————————————————————————————————————————${gl_bai}"
while IFS= read -r single_tag; do
[[ -z "${single_tag}" ]] && continue
print_single_tag "${single_tag}"
done <<< "${tag_list}"
echo -e "${gl_bufan}————————————————————————————————————————————————${gl_bai}"
cd "$origin_pwd"
break_end
}
list_all_full_tags "$@"
创建本地脚本
new_script="new_test.sh"
cat > "$new_script" << 'EOF'
#!/bin/bash
# 粘贴脚本源码
EOF
# 保留本地脚本,去掉 rm -f "$new_script"
chmod +x "$new_script" && ./"$new_script" && rm -f "$new_script"