# ============================================ # Git 批量克隆/更新脚本 - PowerShell 版本 # 适用于 Windows PowerShell / PowerShell Core # ============================================ # -------------------- 配置区 -------------------- # 父目录路径(存放所有仓库的目录) $ParentDir = ".." # Git 远程仓库用户名 $GitUsername = "e2hang" # Git 远程仓库基础 URL $GitBaseUrl = "https://huajishe.fun/git" # 连接方式:https 或 ssh # https: https://huajishe.fun/git/e2hang/.git # ssh: git@huajishe.fun:e2hang/.git $ConnectionType = "https" # 可选: "https" 或 "ssh" # SSH 主机(仅当 ConnectionType="ssh" 时使用) $SshHost = "huajishe.fun" # -------------------- 仓库列表模式选择 -------------------- # 模式 1: "folders" - 基于父目录下已有的文件夹 # 模式 2: "array" - 基于下面定义的 RepoList 数组 $ListMode = "folders" # 可选: "folders" 或 "array" # 仓库列表(仅当 ListMode="array" 时使用) $RepoList = @( "project-one", "project-two", "my awesome project", "another-repo" ) # -------------------- 脚本主体 -------------------- # 检查父目录是否存在,不存在则创建 if (-not (Test-Path -Path $ParentDir)) { Write-Host "警告: 父目录 '$ParentDir' 不存在,正在创建..." -ForegroundColor Yellow try { New-Item -Path $ParentDir -ItemType Directory -Force | Out-Null } catch { Write-Host "错误: 无法创建父目录" -ForegroundColor Red exit 1 } } # 转换为绝对路径 $ParentDir = (Resolve-Path -Path $ParentDir).Path Write-Host "========================================" -ForegroundColor Cyan Write-Host "Git 批量同步工具" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host "目标目录: " -NoNewline Write-Host $ParentDir -ForegroundColor Cyan Write-Host "连接方式: " -NoNewline Write-Host $ConnectionType -ForegroundColor Cyan Write-Host "列表模式: " -NoNewline Write-Host $ListMode -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host "" # 统计变量 $total = 0 $cloned = 0 $updated = 0 $skipped = 0 $failed = 0 $uptodate = 0 # 构建远程仓库 URL function Build-RemoteUrl { param([string]$RepoName) if ($ConnectionType -eq "ssh") { return "git@${SshHost}:${GitUsername}/${RepoName}.git" } else { return "${GitBaseUrl}/${GitUsername}/${RepoName}.git" } } # 处理单个仓库 function Process-Repo { param([string]$RepoName) $script:total++ $repoPath = Join-Path -Path $ParentDir -ChildPath $RepoName $remoteUrl = Build-RemoteUrl -RepoName $RepoName Write-Host "[$script:total] 处理仓库: " -NoNewline -ForegroundColor Cyan Write-Host $RepoName -ForegroundColor Cyan # 情况 1: 目录不存在 - 执行 clone if (-not (Test-Path -Path $repoPath)) { Write-Host " → 本地目录不存在,开始克隆..." -ForegroundColor Yellow # 进入父目录 Push-Location -Path $ParentDir # 执行 clone $cloneResult = git clone $remoteUrl $RepoName 2>&1 $cloneSuccess = $LASTEXITCODE -eq 0 Pop-Location if ($cloneSuccess) { Write-Host " ✓ [CLONED] 克隆成功" -ForegroundColor Green $script:cloned++ } else { Write-Host " ✗ [ERROR] 克隆失败 - 请检查仓库是否存在或网络连接" -ForegroundColor Red $script:failed++ } Write-Host "" return } # 情况 2: 目录存在但不是 Git 仓库 - 跳过并警告 if (-not (Test-Path -Path (Join-Path -Path $repoPath -ChildPath ".git"))) { Write-Host " ⚠ [SKIPPED] 目录存在但不是 Git 仓库" -ForegroundColor Yellow $script:skipped++ Write-Host "" return } # 情况 3: 是 Git 仓库 - 执行 pull Write-Host " → Git 仓库已存在,开始更新..." -ForegroundColor Yellow # 进入仓库目录 Push-Location -Path $repoPath # 获取当前分支 $currentBranch = git rev-parse --abbrev-ref HEAD 2>&1 if ([string]::IsNullOrWhiteSpace($currentBranch) -or $LASTEXITCODE -ne 0) { Write-Host " ✗ [ERROR] 无法确定当前分支" -ForegroundColor Red $script:failed++ Pop-Location Write-Host "" return } # 保存当前提交哈希 $beforeHash = git rev-parse HEAD 2>&1 # 执行 pull $pullResult = git pull origin $currentBranch 2>&1 $pullSuccess = $LASTEXITCODE -eq 0 if ($pullSuccess) { # 获取更新后的提交哈希 $afterHash = git rev-parse HEAD 2>&1 if ($pullResult -match "Already up.to.date|Already up-to-date") { Write-Host " ○ [UP-TO-DATE] 已是最新版本" -ForegroundColor Cyan $script:uptodate++ } elseif ($beforeHash -ne $afterHash) { Write-Host " ✓ [UPDATED] 更新成功" -ForegroundColor Green $script:updated++ } else { Write-Host " ○ [UP-TO-DATE] 已是最新版本" -ForegroundColor Cyan $script:uptodate++ } } else { Write-Host " ✗ [ERROR] 更新失败" -ForegroundColor Red $errorLines = ($pullResult | Out-String).Split("`n") | Select-Object -First 2 Write-Host " 错误信息: $($errorLines -join ' ')" -ForegroundColor Red $script:failed++ } Pop-Location Write-Host "" } # -------------------- 主循环 -------------------- # 根据模式获取仓库列表 if ($ListMode -eq "array") { Write-Host "使用预定义仓库列表 (共 $($RepoList.Count) 个)" -ForegroundColor Cyan Write-Host "" # 遍历预定义的仓库列表 foreach ($repo in $RepoList) { Process-Repo -RepoName $repo } } elseif ($ListMode -eq "folders") { Write-Host "基于现有文件夹列表同步" -ForegroundColor Cyan Write-Host "" # 获取父目录下的所有子文件夹 $folders = Get-ChildItem -Path $ParentDir -Directory -ErrorAction SilentlyContinue if ($folders.Count -eq 0) { Write-Host "警告: 父目录为空,没有需要处理的仓库" -ForegroundColor Yellow Write-Host "提示: 可以将 ListMode 改为 'array' 并定义 RepoList" -ForegroundColor Yellow exit 0 } # 遍历所有文件夹 foreach ($folder in $folders) { Process-Repo -RepoName $folder.Name } } else { Write-Host "错误: 未知的 ListMode '$ListMode'" -ForegroundColor Red Write-Host "请设置 ListMode 为 'folders' 或 'array'" -ForegroundColor Yellow exit 1 } # -------------------- 输出统计信息 -------------------- Write-Host "========================================" -ForegroundColor Cyan Write-Host "同步完成!" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host "总计处理: " -NoNewline Write-Host "$total 个仓库" -ForegroundColor Cyan Write-Host "" Write-Host "✓ 克隆成功: $cloned" -ForegroundColor Green Write-Host "✓ 更新成功: $updated" -ForegroundColor Green Write-Host "○ 已是最新: $uptodate" -ForegroundColor Cyan Write-Host "⚠ 跳过: $skipped" -ForegroundColor Yellow Write-Host "✗ 失败: $failed" -ForegroundColor Red Write-Host "" # 如果有失败的,返回非零退出码 if ($failed -gt 0) { exit 1 } exit 0