327 lines
11 KiB
Bash
327 lines
11 KiB
Bash
#!/usr/bin/env bash
|
||
# ═══════════════════════════════════════════════════════════════
|
||
# git-workflow.sh — ChildHood 项目 Git 工作流自动化
|
||
#
|
||
# 基于 develop 长期开发分支模型。
|
||
# 所有 agent 在 develop 上工作,迭代结束时通过 PR 合并回 main。
|
||
#
|
||
# 用法: bash .claude/scripts/git-workflow.sh <command> [args...]
|
||
#
|
||
# 命令:
|
||
# ready 确保在 develop 上且最新
|
||
# commit <type> <scope> "<msg>" 格式化提交
|
||
# push 推送 develop 到远程
|
||
# submit <issue-number> 一键 commit + push(从 Issue 拉取信息)
|
||
# release [milestone-name] 创建 develop→main 的 PR
|
||
# post-release 合并后同步 main 和 develop
|
||
# catchup 将 develop 合并最新 main 的内容
|
||
# status 显示当前分支和状态
|
||
# ═══════════════════════════════════════════════════════════════
|
||
|
||
set -euo pipefail
|
||
|
||
# ─── 配置 ───
|
||
DEVELOP_BRANCH="develop"
|
||
MAIN_BRANCH="main"
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||
GITEA_PM_CLI="node $PROJECT_ROOT/.claude/skills/gitea-pm/gitea.js"
|
||
GITEA_COLLAB_CLI="node $PROJECT_ROOT/.claude/skills/gitea-collab/gitea.js"
|
||
|
||
# ─── 颜色 ───
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
info() { echo -e "${BLUE}ℹ️ $*${NC}"; }
|
||
ok() { echo -e "${GREEN}✅ $*${NC}"; }
|
||
warn() { echo -e "${YELLOW}⚠️ $*${NC}"; }
|
||
fail() { echo -e "${RED}❌ $*${NC}"; exit 1; }
|
||
|
||
# ─── 当前分支 ───
|
||
current_branch() { git rev-parse --abbrev-ref HEAD; }
|
||
|
||
# ─── 检查是否有未提交的修改 ───
|
||
has_changes() { [ -n "$(git status --porcelain)" ]; }
|
||
|
||
# ─── 检测 UE5 二进制文件 ───
|
||
has_ue5_binaries() {
|
||
git diff --cached --name-only 2>/dev/null | grep -qE '\.(uasset|umap)$'
|
||
}
|
||
|
||
# ═══════════════════════════════════════════════════════════════
|
||
# 命令实现
|
||
# ═══════════════════════════════════════════════════════════════
|
||
|
||
cmd_ready() {
|
||
info "准备工作环境..."
|
||
|
||
local branch
|
||
branch=$(current_branch)
|
||
|
||
# 如果不在 develop 上,切换过去
|
||
if [ "$branch" != "$DEVELOP_BRANCH" ]; then
|
||
if has_changes; then
|
||
warn "有未提交的修改,暂存中..."
|
||
git stash push --include-untracked -m "auto-stash-$(date +%s)"
|
||
fi
|
||
git checkout "$DEVELOP_BRANCH" 2>/dev/null || {
|
||
# 本地没有 develop 分支,从 main 创建
|
||
info "本地没有 $DEVELOP_BRANCH 分支,从 $MAIN_BRANCH 创建..."
|
||
git checkout "$MAIN_BRANCH"
|
||
git pull origin "$MAIN_BRANCH"
|
||
git checkout -b "$DEVELOP_BRANCH"
|
||
}
|
||
fi
|
||
|
||
# 拉取最新 develop
|
||
if git remote get-url origin &>/dev/null; then
|
||
info "拉取远程 $DEVELOP_BRANCH..."
|
||
git pull origin "$DEVELOP_BRANCH" 2>/dev/null || {
|
||
# 远程没有 develop,首次推送
|
||
warn "远程没有 $DEVELOP_BRANCH 分支,将首次推送"
|
||
}
|
||
fi
|
||
|
||
local commit_hash
|
||
commit_hash=$(git rev-parse --short HEAD)
|
||
ok "已在 $DEVELOP_BRANCH 分支上 (${commit_hash})"
|
||
}
|
||
|
||
cmd_commit() {
|
||
local type="${1:-}"
|
||
local scope="${2:-}"
|
||
local message="${3:-}"
|
||
|
||
if [ -z "$type" ] || [ -z "$scope" ] || [ -z "$message" ]; then
|
||
fail "用法: git-workflow.sh commit <type> <scope> \"<message>\"\n 示例: git-workflow.sh commit feat player \"实现角色跳跃\""
|
||
fi
|
||
|
||
# 校验分支
|
||
if [ "$(current_branch)" != "$DEVELOP_BRANCH" ]; then
|
||
warn "当前不在 $DEVELOP_BRANCH 分支上 (当前: $(current_branch))"
|
||
read -rp "继续提交? [y/N] " confirm
|
||
[[ "$confirm" != [yY] ]] && { info "已取消"; return; }
|
||
fi
|
||
|
||
# 暂存所有修改
|
||
if ! has_changes; then
|
||
warn "没有检测到修改"
|
||
return
|
||
fi
|
||
|
||
git add -A
|
||
|
||
# UE5 二进制文件检测
|
||
if has_ue5_binaries; then
|
||
warn "检测到 .uasset/.umap 文件,请确保 commit message 清楚描述了变更内容"
|
||
fi
|
||
|
||
# 格式化 commit message
|
||
local commit_msg="${type}(${scope}): ${message}"
|
||
|
||
# subject ≤ 50 字符检查(仅消息部分)
|
||
local msg_len=${#commit_msg}
|
||
if [ "$msg_len" -gt 72 ]; then
|
||
warn "提交消息较长 ($msg_len 字符),建议精简"
|
||
fi
|
||
|
||
git commit -m "$commit_msg"
|
||
ok "已提交: $commit_msg"
|
||
}
|
||
|
||
cmd_push() {
|
||
local branch
|
||
branch=$(current_branch)
|
||
|
||
info "推送 $branch 到远程..."
|
||
|
||
# 设置上游分支(首次)
|
||
if ! git rev-parse --abbrev-ref "@{upstream}" &>/dev/null; then
|
||
git push -u origin "$branch"
|
||
else
|
||
git push origin "$branch"
|
||
fi
|
||
|
||
ok "已推送 $branch 到远程"
|
||
}
|
||
|
||
cmd_submit() {
|
||
local issue_number="${1:-}"
|
||
if [ -z "$issue_number" ]; then
|
||
fail "用法: git-workflow.sh submit <issue-number>"
|
||
fi
|
||
|
||
info "提交工作 (Issue #$issue_number)..."
|
||
|
||
# 从 Issue 拉取标题作为 commit 参考
|
||
local issue_title=""
|
||
issue_title=$($GITEA_COLLAB_CLI --role dev issue get "$issue_number" --json 2>/dev/null | grep -o '"title":"[^"]*"' | head -1 | sed 's/"title":"//;s/"//') || true
|
||
|
||
# 提交
|
||
if has_changes; then
|
||
if [ -n "$issue_title" ]; then
|
||
info "Issue 标题: $issue_title"
|
||
fi
|
||
warn "有未提交的修改,请先运行: git-workflow.sh commit <type> <scope> \"<message>\""
|
||
return
|
||
fi
|
||
|
||
# 推送
|
||
cmd_push
|
||
|
||
ok "工作已提交到 $DEVELOP_BRANCH (关联 Issue #$issue_number)"
|
||
}
|
||
|
||
cmd_release() {
|
||
local milestone_name="${1:-}"
|
||
|
||
info "准备发布 PR ($DEVELOP_BRANCH → $MAIN_BRANCH)..."
|
||
|
||
# 确保在 develop 上
|
||
if [ "$(current_branch)" != "$DEVELOP_BRANCH" ]; then
|
||
fail "请先切换到 $DEVELOP_BRANCH 分支"
|
||
fi
|
||
|
||
# 确保本地最新
|
||
git pull origin "$DEVELOP_BRANCH"
|
||
|
||
# 获取里程碑名称
|
||
if [ -z "$milestone_name" ]; then
|
||
# 尝试从当前里程碑获取
|
||
milestone_name=$($GITEA_PM_CLI --role pm milestone list --state open --json 2>/dev/null | grep -o '"title":"[^"]*"' | head -1 | sed 's/"title":"//;s/"//') || "迭代发布"
|
||
if [ -z "$milestone_name" ]; then
|
||
milestone_name="迭代发布"
|
||
fi
|
||
fi
|
||
|
||
local pr_title="Merge develop → main: ${milestone_name}"
|
||
|
||
# 构造 PR body(汇总已关闭的 Issue)
|
||
local pr_body="## 发布合并\n\n将 \`${DEVELOP_BRANCH}\` 分支的成果合并到 \`${MAIN_BRANCH}\`。\n\n### 里程碑\n${milestone_name}"
|
||
|
||
# 创建 PR
|
||
info "创建 PR: $pr_title"
|
||
local pr_result
|
||
pr_result=$($GITEA_PM_CLI --role pm pr create \
|
||
--base "$MAIN_BRANCH" \
|
||
--head "$DEVELOP_BRANCH" \
|
||
--title "$pr_title" \
|
||
--body "$(echo -e "$pr_body")" \
|
||
--json 2>&1) || {
|
||
fail "创建 PR 失败: $pr_result"
|
||
}
|
||
|
||
local pr_number
|
||
pr_number=$(echo "$pr_result" | grep -o '"number":[0-9]*' | head -1 | sed 's/"number"://') || true
|
||
|
||
if [ -n "$pr_number" ]; then
|
||
ok "PR #$pr_number 已创建: $pr_title"
|
||
info "请在 Gitea 审查并合并: http://micecola.top:8418/starmen1265/ChildHood/pulls/$pr_number"
|
||
else
|
||
ok "PR 已创建,请查看 Gitea"
|
||
fi
|
||
}
|
||
|
||
cmd_post_release() {
|
||
info "合并后同步..."
|
||
|
||
# 同步 main
|
||
info "同步 $MAIN_BRANCH..."
|
||
git checkout "$MAIN_BRANCH"
|
||
git pull origin "$MAIN_BRANCH"
|
||
ok "$MAIN_BRANCH 已更新"
|
||
|
||
# 切回 develop 并合并 main(保持 develop 包含 merge commit)
|
||
info "同步 $DEVELOP_BRANCH..."
|
||
git checkout "$DEVELOP_BRANCH"
|
||
git merge "$MAIN_BRANCH" --no-edit
|
||
git push origin "$DEVELOP_BRANCH"
|
||
ok "$DEVELOP_BRANCH 已同步(包含 $MAIN_BRANCH 的 merge commit)"
|
||
|
||
local commit_hash
|
||
commit_hash=$(git rev-parse --short HEAD)
|
||
ok "完成,当前在 $DEVELOP_BRANCH (${commit_hash})"
|
||
}
|
||
|
||
cmd_catchup() {
|
||
info "将 develop 跟上最新的 $MAIN_BRANCH..."
|
||
|
||
if [ "$(current_branch)" != "$DEVELOP_BRANCH" ]; then
|
||
fail "请先切换到 $DEVELOP_BRANCH 分支"
|
||
fi
|
||
|
||
git fetch origin
|
||
git merge "origin/$MAIN_BRANCH" --no-edit
|
||
ok "$DEVELOP_BRANCH 已合并最新 $MAIN_BRANCH"
|
||
}
|
||
|
||
cmd_status() {
|
||
local branch
|
||
branch=$(current_branch)
|
||
local commit_hash
|
||
commit_hash=$(git rev-parse --short HEAD)
|
||
local changed
|
||
changed=$(git status --porcelain | wc -l | tr -d ' ')
|
||
|
||
echo -e "${BLUE}═══ Git 工作流状态 ═══${NC}"
|
||
echo " 当前分支: ${branch} (${commit_hash})"
|
||
|
||
if [ "$branch" = "$DEVELOP_BRANCH" ]; then
|
||
echo -e " ${GREEN}✓ 在 develop 开发分支上${NC}"
|
||
elif [ "$branch" = "$MAIN_BRANCH" ]; then
|
||
echo -e " ${YELLOW}⚠ 在 main 分支上,请切换到 develop 开始工作${NC}"
|
||
else
|
||
echo -e " ${YELLOW}⚠ 在非标准分支上: $branch${NC}"
|
||
fi
|
||
|
||
echo " 未提交修改: ${changed} 个文件"
|
||
|
||
if [ "$changed" -gt 0 ]; then
|
||
echo ""
|
||
git status --short
|
||
fi
|
||
|
||
# 远程同步状态
|
||
if git rev-parse "@{upstream}" &>/dev/null; then
|
||
local ahead behind
|
||
ahead=$(git rev-list --count "@{upstream}..HEAD" 2>/dev/null || echo "0")
|
||
behind=$(git rev-list --count "HEAD..@{upstream}" 2>/dev/null || echo "0")
|
||
echo " 远程状态: ahead ${ahead}, behind ${behind}"
|
||
fi
|
||
}
|
||
|
||
# ═══════════════════════════════════════════════════════════════
|
||
# 入口
|
||
# ═══════════════════════════════════════════════════════════════
|
||
|
||
case "${1:-}" in
|
||
ready) cmd_ready ;;
|
||
commit) shift; cmd_commit "$@" ;;
|
||
push) cmd_push ;;
|
||
submit) shift; cmd_submit "$@" ;;
|
||
release) shift; cmd_release "$@" ;;
|
||
post-release) cmd_post_release ;;
|
||
catchup) cmd_catchup ;;
|
||
status) cmd_status ;;
|
||
*)
|
||
echo "git-workflow.sh — ChildHood 项目 Git 工作流自动化"
|
||
echo ""
|
||
echo "用法: bash .claude/scripts/git-workflow.sh <command> [args...]"
|
||
echo ""
|
||
echo "命令:"
|
||
echo " ready 确保在 develop 上且最新"
|
||
echo " commit <type> <scope> \"<msg>\" 格式化提交"
|
||
echo " push 推送 develop 到远程"
|
||
echo " submit <issue-number> 推送并关联 Issue"
|
||
echo " release [milestone-name] 创建 develop→main PR"
|
||
echo " post-release 合并后同步 main 和 develop"
|
||
echo " catchup 将 develop 合并最新 main"
|
||
echo " status 显示当前分支和状态"
|
||
echo ""
|
||
echo "工作流模型: develop 长期开发分支 → 迭代完成时 PR 合并回 main"
|
||
;;
|
||
esac
|