Instantly share code, notes, and snippets.
Last active
September 27, 2025 05:04
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
-
Save millken/bf05c02db74b1f5214fa57e41232589a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # 获取项目根目录 | |
| root_dir=$(pwd) | |
| # 检查路径是否被 .gitignore 忽略 | |
| is_ignored() { | |
| local path="$1" | |
| # 使用 git check-ignore 判断,静默处理错误(非 git 仓库时视为未忽略) | |
| if git check-ignore -q "$path" 2>/dev/null; then | |
| return 0 | |
| fi | |
| return 1 | |
| } | |
| # 函数:为指定模块创建标签 | |
| create_tag_for_module() { | |
| local module_dir=$1 | |
| local module_name=$1 | |
| # 如果模块被 .gitignore 忽略,则跳过 | |
| if is_ignored "$module_dir"; then | |
| echo -e "\033[33mSkipping ignored module $module_dir (listed in .gitignore)\033[0m" | |
| return 0 | |
| fi | |
| # 切换到模块目录 | |
| cd "$module_dir" || { echo -e "\033[31mFailed to cd to $module_dir\033[0m"; return 1; } | |
| # 输入前先高亮显示该模块已有标签 | |
| show_module_tags "$module_name" | |
| # 提示用户输入版本号,直到格式合法;按 ESC 或空行取消 | |
| while true; do | |
| read -r -p "Enter version for $module_name (e.g., 1.0.0) (press ESC to cancel): " version | |
| # 取消条件:包含 ESC 字符或为空字符串 | |
| if [[ "$version" == *$'\e'* ]] || [ -z "$version" ]; then | |
| echo -e "\033[33mCancelled version input. Returning to menu.\033[0m" | |
| cd "$root_dir" | |
| return 0 | |
| fi | |
| # 版本格式校验 | |
| if [[ ! $version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | |
| echo -e "\033[31mInvalid version format. Use MAJOR.MINOR.PATCH (e.g., 1.2.3).\033[0m" | |
| continue | |
| fi | |
| # 组合标签名并检查是否已存在 | |
| tag_name="${module_name}/v${version}" | |
| if git show-ref --tags --verify --quiet "refs/tags/${tag_name}"; then | |
| echo -e "\033[31mTag already exists: \033[1;33m${tag_name}\033[0m" | |
| # 再次展示已有标签,帮助用户选择新版本 | |
| show_module_tags "$module_name" | |
| continue | |
| fi | |
| break | |
| done | |
| # 创建标签(使用轻量级标签) | |
| git tag "$tag_name" | |
| echo -e "\033[32mCreated tag $tag_name for $module_name\033[0m" | |
| # 返回到根目录 | |
| cd "$root_dir" | |
| } | |
| # 函数:显示特定模块的标签历史 | |
| show_module_tags() { | |
| local module_name=$1 | |
| # 标题:加粗并使用黄色背景高亮 | |
| echo -e "\033[1;30;43m Tags for module ${module_name} \033[0m" | |
| # 列出标签并逐行高亮显示,每行加粗并使用青色前缀 | |
| git tag -l "${module_name}/*" --sort=-v:refname | while read -r tag; do | |
| if [ -n "$tag" ]; then | |
| echo -e "\033[1;36m> \033[1;33m${tag}\033[0m" | |
| fi | |
| done | |
| } | |
| # 主菜单 | |
| while true; do | |
| echo " | |
| 1. Tag all modules | |
| 2. Tag a specific module | |
| 3. Show tags for a module | |
| 4. Push all tags to remote | |
| 5. Force sync remote tags (delete local and re-fetch) | |
| 6. Exit | |
| " | |
| read -p "Choose an option: " choice | |
| case $choice in | |
| 1) | |
| # 为所有模块创建标签 | |
| for module_dir in $(find . -name go.mod -exec dirname {} \;); do | |
| # 去掉前缀 "./" | |
| dir="${module_dir#./}" | |
| # 跳过当前目录 | |
| if [ -z "$dir" ] || [ "$dir" = "." ]; then | |
| continue | |
| fi | |
| # 跳过被 .gitignore 忽略的目录 | |
| if is_ignored "$dir"; then | |
| echo -e "\033[33mIgnored by .gitignore: $dir\033[0m" | |
| continue | |
| fi | |
| # 处理模块目录 | |
| # create_tag_for_module "$dir" | |
| echo "$dir" | |
| done | |
| ;; | |
| 2) | |
| # 为特定模块创建标签,允许重试,按 ESC 取消回到上级菜单 | |
| while true; do | |
| read -r -p "Enter module name (press ESC to cancel): " module_name | |
| # 如果输入包含 ESC 字符,则取消 | |
| if [[ "$module_name" == *$'\e'* ]] || [ -z "$module_name" ]; then | |
| echo -e "\033[33mCancelled. Returning to menu.\033[0m" | |
| break | |
| fi | |
| if [ -d "$module_name" ] && [ -f "$module_name/go.mod" ]; then | |
| if is_ignored "$module_name"; then | |
| echo -e "\033[33mModule $module_name is ignored by .gitignore. Skipping.\033[0m" | |
| break | |
| else | |
| create_tag_for_module "$module_name" | |
| break | |
| fi | |
| else | |
| echo -e "\033[31mModule not found or invalid. Try again or press ESC to cancel.\033[0m" | |
| fi | |
| done | |
| ;; | |
| 3) | |
| # 显示特定模块的标签 | |
| while true; do | |
| read -r -p "Enter module name to show tags (press ESC to cancel): " module_name | |
| if [[ "$module_name" == *$'\e'* ]] || [ -z "$module_name" ]; then | |
| echo -e "\033[33mCancelled. Returning to menu.\033[0m" | |
| break | |
| fi | |
| if [ -d "$module_name" ] && [ -f "$module_name/go.mod" ]; then | |
| show_module_tags "$module_name" | |
| break | |
| else | |
| echo -e "\033[31mModule not found or invalid. Try again or press ESC to cancel.\033[0m" | |
| fi | |
| done | |
| ;; | |
| 4) | |
| # 推送所有标签到远程仓库 | |
| git push --tags | |
| echo -e "\033[32mAll tags have been pushed to the remote repository.\033[0m" | |
| ;; | |
| 5) | |
| # 强制同步远程 tags:确认并执行删除本地 tags 然后从远程拉取 | |
| while true; do | |
| read -r -p "This will delete all local tags and re-fetch from remote. Continue? (y/N): " confirm | |
| if [[ "${confirm}" == *$'\e'* ]] || [ -z "${confirm}" ]; then | |
| echo -e "\033[33mCancelled. Returning to menu.\033[0m" | |
| break | |
| fi | |
| if [[ "${confirm}" =~ ^[Yy]$ ]]; then | |
| echo -e "\033[33mFetching all remotes and pruning...\033[0m" | |
| git fetch --all --prune | |
| echo -e "\033[33mDeleting all local tags...\033[0m" | |
| # delete all local tags (xargs -r avoids errors if none) | |
| git tag -l | xargs -r git tag -d | |
| echo -e "\033[33mFetching tags from origin...\033[0m" | |
| git fetch --tags origin | |
| echo -e "\033[32mTags synchronized from remote.\033[0m" | |
| break | |
| else | |
| echo -e "\033[33mCancelled. Returning to menu.\033[0m" | |
| break | |
| fi | |
| done | |
| ;; | |
| 6) | |
| # 退出 | |
| echo -e "\033[32mExiting.\033[0m" | |
| exit 0 | |
| ;; | |
| *) | |
| echo -e "\033[31mInvalid option. Please try again.\033[0m" | |
| ;; | |
| esac | |
| done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment