config(git): 引入develop长期开发分支模型和git工作流自动化

This commit is contained in:
2026-06-11 15:24:38 +08:00
parent 3b851a195e
commit ac7a3abda9
12 changed files with 781 additions and 72 deletions
+326
View File
@@ -0,0 +1,326 @@
#!/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