Files
workspace/bash/git-renew-linux.sh
2026-03-15 13:14:04 +08:00

247 lines
7.2 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# ============================================
# Git 批量克隆/更新脚本 - Bash 版本
# 适用于 Linux / macOS / Git Bash
# ============================================
# -------------------- 配置区 --------------------
# 父目录路径(存放所有仓库的目录)
PARENT_DIR=".."
# Git 远程仓库用户名
GIT_USERNAME="e2hang"
# Git 远程仓库基础 URL
GIT_BASE_URL="https://huajishe.fun/git"
# 连接方式https 或 ssh
# https: https://huajishe.fun/git/e2hang/<repo>.git
# ssh: git@huajishe.fun:e2hang/<repo>.git
CONNECTION_TYPE="https" # 可选: "https" 或 "ssh"
# SSH 主机(仅当 CONNECTION_TYPE="ssh" 时使用)
SSH_HOST="huajishe.fun"
# -------------------- 仓库列表模式选择 --------------------
# 模式 1: "folders" - 基于父目录下已有的文件夹
# 模式 2: "array" - 基于下面定义的 REPO_LIST 数组
LIST_MODE="folders" # 可选: "folders" 或 "array"
# 仓库列表(仅当 LIST_MODE="array" 时使用)
# 在这里定义你想要同步的仓库名
REPO_LIST=(
"project-one"
"project-two"
"my awesome project"
"another-repo"
)
# -------------------- 脚本主体 --------------------
# 颜色定义
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# 检查父目录是否存在,不存在则创建
if [ ! -d "$PARENT_DIR" ]; then
echo -e "${YELLOW}警告: 父目录 '$PARENT_DIR' 不存在,正在创建...${NC}"
mkdir -p "$PARENT_DIR" || {
echo -e "${RED}错误: 无法创建父目录${NC}"
exit 1
}
fi
# 转换为绝对路径
PARENT_DIR=$(cd "$PARENT_DIR" && pwd)
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}Git 批量同步工具${NC}"
echo -e "${BLUE}========================================${NC}"
echo -e "目标目录: ${CYAN}$PARENT_DIR${NC}"
echo -e "连接方式: ${CYAN}$CONNECTION_TYPE${NC}"
echo -e "列表模式: ${CYAN}$LIST_MODE${NC}"
echo -e "${BLUE}========================================${NC}"
echo ""
# 统计变量
total=0
cloned=0
updated=0
skipped=0
failed=0
uptodate=0
# 构建远程仓库 URL
# 参数: $1 = 仓库名
build_remote_url() {
local repo_name="$1"
if [ "$CONNECTION_TYPE" = "ssh" ]; then
echo "git@${SSH_HOST}:${GIT_USERNAME}/${repo_name}.git"
else
echo "${GIT_BASE_URL}/${GIT_USERNAME}/${repo_name}.git"
fi
}
# 处理单个仓库
# 参数: $1 = 仓库名
process_repo() {
local repo_name="$1"
local repo_path="$PARENT_DIR/$repo_name"
local remote_url=$(build_remote_url "$repo_name")
((total++))
echo -e "${BLUE}[$total] 处理仓库: ${CYAN}$repo_name${NC}"
# 情况 1: 目录不存在 - 执行 clone
if [ ! -d "$repo_path" ]; then
echo -e "${YELLOW} → 本地目录不存在,开始克隆...${NC}"
# 进入父目录
cd "$PARENT_DIR" || {
echo -e "${RED} ✗ [ERROR] 无法进入父目录${NC}"
((failed++))
echo ""
return
}
# 执行 clone
if git clone "$remote_url" "$repo_name" 2>&1 | grep -q "Cloning into\|done"; then
echo -e "${GREEN} ✓ [CLONED] 克隆成功${NC}"
((cloned++))
else
echo -e "${RED} ✗ [ERROR] 克隆失败 - 请检查仓库是否存在或网络连接${NC}"
((failed++))
fi
echo ""
return
fi
# 情况 2: 目录存在但不是 Git 仓库 - 跳过并警告
if [ ! -d "$repo_path/.git" ]; then
echo -e "${YELLOW} ⚠ [SKIPPED] 目录存在但不是 Git 仓库${NC}"
((skipped++))
echo ""
return
fi
# 情况 3: 是 Git 仓库 - 执行 pull
echo -e "${YELLOW} → Git 仓库已存在,开始更新...${NC}"
# 进入仓库目录
cd "$repo_path" || {
echo -e "${RED} ✗ [ERROR] 无法进入仓库目录${NC}"
((failed++))
echo ""
return
}
# 获取当前分支
current_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
if [ -z "$current_branch" ]; then
echo -e "${RED} ✗ [ERROR] 无法确定当前分支${NC}"
((failed++))
echo ""
return
fi
# 保存当前提交哈希(用于判断是否有更新)
before_hash=$(git rev-parse HEAD 2>/dev/null)
# 执行 pull
pull_output=$(git pull origin "$current_branch" 2>&1)
pull_exit_code=$?
if [ $pull_exit_code -eq 0 ]; then
# 获取更新后的提交哈希
after_hash=$(git rev-parse HEAD 2>/dev/null)
if echo "$pull_output" | grep -q "Already up to date\|Already up-to-date"; then
echo -e "${CYAN} ○ [UP-TO-DATE] 已是最新版本${NC}"
((uptodate++))
elif [ "$before_hash" != "$after_hash" ]; then
echo -e "${GREEN} ✓ [UPDATED] 更新成功${NC}"
((updated++))
else
echo -e "${CYAN} ○ [UP-TO-DATE] 已是最新版本${NC}"
((uptodate++))
fi
else
echo -e "${RED} ✗ [ERROR] 更新失败${NC}"
echo -e "${RED} 错误信息: $(echo "$pull_output" | head -n 2)${NC}"
((failed++))
fi
echo ""
}
# -------------------- 主循环 --------------------
# 根据模式获取仓库列表
if [ "$LIST_MODE" = "array" ]; then
echo -e "${CYAN}使用预定义仓库列表 (共 ${#REPO_LIST[@]} 个)${NC}"
echo ""
# 遍历预定义的仓库列表
for repo in "${REPO_LIST[@]}"; do
process_repo "$repo"
done
elif [ "$LIST_MODE" = "folders" ]; then
echo -e "${CYAN}基于现有文件夹列表同步${NC}"
echo ""
# 检查父目录下是否有子文件夹
if [ -z "$(ls -A "$PARENT_DIR" 2>/dev/null)" ]; then
echo -e "${YELLOW}警告: 父目录为空,没有需要处理的仓库${NC}"
echo -e "${YELLOW}提示: 可以将 LIST_MODE 改为 'array' 并定义 REPO_LIST${NC}"
exit 0
fi
# 遍历父目录下的所有一级子目录
for repo_path in "$PARENT_DIR"/*/; do
# 去除末尾的斜杠
repo_path="${repo_path%/}"
# 跳过不是目录的项
if [ ! -d "$repo_path" ]; then
continue
fi
# 获取文件夹名
repo_name=$(basename "$repo_path")
# 处理仓库(这里是 pull 操作)
process_repo "$repo_name"
done
else
echo -e "${RED}错误: 未知的 LIST_MODE '$LIST_MODE'${NC}"
echo -e "${YELLOW}请设置 LIST_MODE 为 'folders' 或 'array'${NC}"
exit 1
fi
# -------------------- 输出统计信息 --------------------
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}同步完成!${NC}"
echo -e "${BLUE}========================================${NC}"
echo -e "总计处理: ${CYAN}$total${NC} 个仓库"
echo ""
echo -e "${GREEN}✓ 克隆成功: $cloned${NC}"
echo -e "${GREEN}✓ 更新成功: $updated${NC}"
echo -e "${CYAN}○ 已是最新: $uptodate${NC}"
echo -e "${YELLOW}⚠ 跳过: $skipped${NC}"
echo -e "${RED}✗ 失败: $failed${NC}"
echo ""
# 如果有失败的,返回非零退出码
if [ $failed -gt 0 ]; then
exit 1
fi
exit 0