#!/bin/bash # git-ops.sh - Git 操作封装 # 用法: # ./git-ops.sh clone - 克隆仓库 # ./git-ops.sh pull - 拉取更新 # ./git-ops.sh checkout - 切换版本 # ./git-ops.sh fetch - 获取远程更新 # ./git-ops.sh status - 查看状态 # ./git-ops.sh has-updates - 检查是否有更新 set -e SKILLS_DIR="$HOME/.claude/skills" REPOS_DIR="$SKILLS_DIR/repos" REGISTRY_SCRIPT="$SKILLS_DIR/skill-manager/scripts/registry.sh" # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # 从 URL 提取技能名称 extract_name() { local repo="$1" # 处理各种格式 # https://github.com/org/skill-name.git -> skill-name # git@github.com:org/skill-name.git -> skill-name echo "$repo" | sed -E 's|.*/([^/]+)(\.git)?$|\1|' | sed 's/\.git$//' } # 克隆仓库 cmd_clone() { local repo="$1" local name="${2:-$(extract_name "$repo")}" if [ -z "$repo" ]; then echo -e "${RED}用法: git-ops.sh clone [name]${NC}" exit 1 fi local target_dir="$REPOS_DIR/$name" # 检查是否已存在 if [ -d "$target_dir" ]; then echo -e "${YELLOW}技能已存在: $name${NC}" echo "使用 'git-ops.sh pull $name' 更新" exit 1 fi echo -e "${BLUE}克隆技能: $name${NC}" echo "仓库: $repo" echo "目标: $target_dir" echo "----------------------------------------" # 确保 repos 目录存在 mkdir -p "$REPOS_DIR" # 克隆仓库 if git clone "$repo" "$target_dir"; then echo -e "${GREEN}✓ 克隆成功${NC}" # 检查 skill.yaml if [ ! -f "$target_dir/skill.yaml" ]; then echo -e "${YELLOW}⚠ 警告: 未找到 skill.yaml${NC}" fi # 获取版本 local version="unknown" if [ -f "$target_dir/skill.yaml" ] && command -v yq &> /dev/null; then version=$(yq e '.version // "1.0.0"' "$target_dir/skill.yaml") fi # 添加到 registry "$REGISTRY_SCRIPT" add "$name" "$repo" "$version" echo -e "${GREEN}✓ 技能安装完成: $name ($version)${NC}" else echo -e "${RED}✗ 克隆失败${NC}" exit 1 fi } # 拉取更新 cmd_pull() { local name="$1" if [ -z "$name" ]; then echo -e "${RED}用法: git-ops.sh pull ${NC}" exit 1 fi local repo_dir="$REPOS_DIR/$name" if [ ! -d "$repo_dir" ]; then echo -e "${RED}技能不存在: $name${NC}" exit 1 fi echo -e "${BLUE}更新技能: $name${NC}" echo "----------------------------------------" cd "$repo_dir" # 获取当前版本 local old_version="unknown" if [ -f "skill.yaml" ] && command -v yq &> /dev/null; then old_version=$(yq e '.version // "unknown"' skill.yaml) fi # 拉取更新 if git pull origin main 2>/dev/null || git pull origin master 2>/dev/null; then # 获取新版本 local new_version="unknown" if [ -f "skill.yaml" ] && command -v yq &> /dev/null; then new_version=$(yq e '.version // "unknown"' skill.yaml) fi if [ "$old_version" != "$new_version" ]; then echo -e "${GREEN}✓ 版本更新: $old_version → $new_version${NC}" "$REGISTRY_SCRIPT" update "$name" version "$new_version" else echo -e "${GREEN}✓ 已是最新版本: $new_version${NC}" fi # 更新 last_updated "$REGISTRY_SCRIPT" update "$name" last_updated "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" else echo -e "${RED}✗ 更新失败${NC}" exit 1 fi } # 切换版本 cmd_checkout() { local name="$1" local ref="$2" if [ -z "$name" ] || [ -z "$ref" ]; then echo -e "${RED}用法: git-ops.sh checkout ${NC}" exit 1 fi local repo_dir="$REPOS_DIR/$name" if [ ! -d "$repo_dir" ]; then echo -e "${RED}技能不存在: $name${NC}" exit 1 fi echo -e "${BLUE}切换版本: $name → $ref${NC}" echo "----------------------------------------" cd "$repo_dir" # 获取当前版本 local old_ref=$(git describe --tags --always 2>/dev/null || git rev-parse --short HEAD) # 切换版本 if git checkout "$ref" 2>/dev/null; then echo -e "${GREEN}✓ 版本切换: $old_ref → $ref${NC}" # 更新 registry "$REGISTRY_SCRIPT" update "$name" version "$ref" "$REGISTRY_SCRIPT" update "$name" last_updated "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" else echo -e "${RED}✗ 切换失败: $ref 不存在${NC}" echo "可用的 tag:" git tag -l | head -10 exit 1 fi } # 获取远程更新 cmd_fetch() { local name="$1" if [ -z "$name" ]; then echo -e "${RED}用法: git-ops.sh fetch ${NC}" exit 1 fi local repo_dir="$REPOS_DIR/$name" if [ ! -d "$repo_dir" ]; then echo -e "${RED}技能不存在: $name${NC}" exit 1 fi cd "$repo_dir" git fetch origin --tags --quiet echo -e "${GREEN}✓ 已获取远程更新: $name${NC}" } # 查看状态 cmd_status() { local name="$1" if [ -z "$name" ]; then echo -e "${RED}用法: git-ops.sh status ${NC}" exit 1 fi local repo_dir="$REPOS_DIR/$name" if [ ! -d "$repo_dir" ]; then echo -e "${RED}技能不存在: $name${NC}" exit 1 fi echo -e "${BLUE}技能状态: $name${NC}" echo "----------------------------------------" cd "$repo_dir" local branch=$(git branch --show-current 2>/dev/null || echo "detached") local commit=$(git rev-parse --short HEAD) local remote_url=$(git config --get remote.origin.url) echo "分支: $branch" echo "Commit: $commit" echo "远程: $remote_url" if [ -f "skill.yaml" ] && command -v yq &> /dev/null; then local version=$(yq e '.version // "unknown"' skill.yaml) echo "版本: $version" fi echo "" echo "最近提交:" git log --oneline -3 } # 检查是否有更新 cmd_has_updates() { local name="$1" if [ -z "$name" ]; then echo -e "${RED}用法: git-ops.sh has-updates ${NC}" exit 1 fi local repo_dir="$REPOS_DIR/$name" if [ ! -d "$repo_dir" ]; then echo -e "${RED}技能不存在: $name${NC}" exit 1 fi cd "$repo_dir" # 获取远程更新 git fetch origin --quiet 2>/dev/null || true # 比较本地和远程 local local_head=$(git rev-parse HEAD) local remote_head=$(git rev-parse origin/main 2>/dev/null || git rev-parse origin/master 2>/dev/null || echo "") if [ -z "$remote_head" ]; then echo "unknown" exit 0 fi if [ "$local_head" != "$remote_head" ]; then echo "yes" # 显示更新数量 local behind=$(git rev-list HEAD..origin/main --count 2>/dev/null || git rev-list HEAD..origin/master --count 2>/dev/null || echo "0") echo "behind: $behind commits" else echo "no" fi } # 主命令分发 case "${1:-help}" in clone) cmd_clone "$2" "$3" ;; pull) cmd_pull "$2" ;; checkout) cmd_checkout "$2" "$3" ;; fetch) cmd_fetch "$2" ;; status) cmd_status "$2" ;; has-updates) cmd_has_updates "$2" ;; *) echo "用法: git-ops.sh [args]" echo "" echo "命令:" echo " clone [name] 克隆仓库" echo " pull 拉取更新" echo " checkout 切换版本" echo " fetch 获取远程更新" echo " status 查看状态" echo " has-updates 检查是否有更新" ;; esac