Skip to content

Instantly share code, notes, and snippets.

@Wxh16144
Last active March 3, 2026 09:46
Show Gist options
  • Select an option

  • Save Wxh16144/e6231fabd1ad4374618e976bc0456467 to your computer and use it in GitHub Desktop.

Select an option

Save Wxh16144/e6231fabd1ad4374618e976bc0456467 to your computer and use it in GitHub Desktop.
Auto Update Repos Script
#!/bin/bash
# 配置:定义仓库路径,格式为 "路径|分支|命令"
# - 分支:可选。指定要拉取的分支,如 "main" 或 "develop"。留空则使用当前检出的分支。
# - 命令:可选。pull 成功后执行的命令。
#
# 示例:
# "path/to/repo|main|npm install" -> 强制 main 分支,执行 npm install
# "path/to/repo||npm install" -> 跟随当前分支,执行 npm install
# "path/to/repo|develop" -> 强制 develop 分支,无后续命令
# "path/to/repo" -> 最简配置:跟随当前分支,无命令
repos=(
"/Users/wuxh/Code/company/preview/common-editor|develop"
"/Users/wuxh/Code/company/preview/savery-editor|develop"
"/Users/wuxh/Code/company/saveryconfig"
"/Users/wuxh/Code/company/savery-webgpu||./fast-webgpu"
)
# 可选:定义全局默认分支(仅当配置中分支字段为空,且这里设置了值时生效。留空则默认各自的当前分支)
default_global_branch=""
echo "---------------------------- $(date +'%Y-%m-%d %H:%M:%S') ----------------------------"
current_date=$(date +%Y%m%d)
result=""
for item in "${repos[@]}"; do
# 解析配置项
# 使用 IFS 将字符串分割为数组
IFS='|' read -r -a config <<<"$item"
repo_path="${config[0]}"
target_repo_branch="${config[1]}"
post_cmd="${config[2]}"
# 去除可能的前后空格(虽通常不建议路径带空格,但也防一手)
repo_path=$(echo "$repo_path" | xargs)
target_repo_branch=$(echo "$target_repo_branch" | xargs)
post_cmd=$(echo "$post_cmd" | xargs)
# 检查目录是否存在
if [ ! -d "$repo_path" ]; then
echo "🚫 目录未找到: $repo_path"
result="$result\n🚫 $(basename "$repo_path") (未找到)"
continue
fi
# 检查是否为 git 仓库
if [ -d "$repo_path/.git" ]; then
echo
echo "🚀 正在处理: $repo_path"
# 进入目录
cd "$repo_path" || {
echo "❌ 无法进入目录: $repo_path"
result="$result\n❌ $(basename "$repo_path") (拒绝访问)"
continue
}
short_dir="$(basename "$(dirname "$repo_path")")/$(basename "$repo_path")"
current_branch=$(git rev-parse --abbrev-ref HEAD)
# 1. 先检查当前状态,如果有未提交更改,先 stash 起来,避免切换分支失败
if [[ -n $(git status --porcelain) ]]; then
echo "📦 当前目录不干净 ($current_branch),正在暂存(Stash)更改(包含新建文件)..."
git stash save -u "auto_stash_$current_date"
fi
# 2. 确定要拉取的最终目标分支
# 优先级:单项配置 > 全局默认
final_target_branch=""
if [[ -n "$target_repo_branch" ]]; then
final_target_branch="$target_repo_branch"
elif [[ -n "$default_global_branch" ]]; then
final_target_branch="$default_global_branch"
fi
# 3. 如果指定了目标分支且与当前不一致,则切换
if [[ -n "$final_target_branch" && "$current_branch" != "$final_target_branch" ]]; then
echo "⚠️ 检测到当前分支 ($current_branch) 与目标 ($final_target_branch) 不一致,正在切换..."
git checkout "$final_target_branch"
if [[ $? -ne 0 ]]; then
echo "❌ 切换到 $final_target_branch 失败,跳过..."
result="$result\n❌ $short_dir (切换失败)"
continue
fi
# 更新当前分支变量
current_branch="$final_target_branch"
fi
echo "⬇️ 正在拉取 origin $current_branch..."
pull_output=$(git pull origin "$current_branch" 2>&1)
pull_exit_code=$?
# Output the pull result to console so user can see details if running manually
echo "$pull_output"
if [ $pull_exit_code -eq 0 ]; then
status_icon="✅"
extra_msg=""
current_hash=$(git rev-parse --short HEAD)
# Detect if there were actual updates
status_no_change=""
has_updates=false
if [[ "$pull_output" == *"Already up to date."* ]]; then
status_no_change=" (无变动)"
else
status_no_change=" 🆙"
has_updates=true
fi
# 如果存在、拉取成功且有代码变更,则执行后置命令
if [[ -n "$post_cmd" ]]; then
if [[ "$has_updates" == "true" ]]; then
echo "⚙️ 检测到代码更新,执行后置命令: $post_cmd"
if eval "$post_cmd"; then
extra_msg=" + 命令成功"
else
status_icon="⚠️ "
extra_msg=" + 命令失败"
echo "❌ 后置命令失败。"
fi
else
echo "💤 无代码变更,跳过后置命令。"
fi
fi
result="${result}\n${status_icon} ${short_dir} (${current_branch} @ ${current_hash})${status_no_change}${extra_msg}"
else
echo "❌ 拉取目录 $repo_path 失败"
result="${result}\n❌ ${short_dir} (拉取失败)"
fi
echo
else
echo "🚫 $repo_path 不是有效的 git 仓库。"
result="${result}\n🚫 $(basename "$repo_path") (非 git 仓库)"
fi
done
echo
echo "============================================================"
echo -e "📊 执行汇总报告: $(date +'%Y-%m-%d %H:%M:%S') $result"
echo "============================================================"
echo
@Wxh16144
Copy link
Author

Auto Update Repos Script

这个脚本用于批量更新多个 Git 仓库,支持自动处理未提交的更改、切换分支以及执行更新后的命令。

功能特性

  1. 批量更新:一次性拉取多个仓库的最新代码。
  2. 分支管理:可配置指定拉取特定的分支。如果不一致会自动切换。
  3. 自动暂存:如果本地有未提交的更改(包括新增文件),会自动执行 git stash 暂存,防止冲突。
  4. 后置命令:支持在拉取成功后执行自定义 Shell 命令(如 npm install)。

配置说明

编辑脚本文件 auto-update-repos.sh 中的 repos 数组进行配置。

配置格式

"绝对路径|分支名|后置命令"
  • 路径:仓库的绝对路径(必填)。
  • 分支名:要拉取的目标分支(选填)。留空则使用当前所在分支。
  • 后置命令:更新成功后执行的命令(选填)。

示例配置

repos=(
    # 强制拉取 main 分支,并执行安装和构建
    "/Users/name/project-a|main|npm install && npm run build"

    # 强制拉取 develop 分支,无后续命令
    "/Users/name/project-b|develop"

    # 保持当前分支,更新后运行 setup
    "/Users/name/project-c||make setup"

    # 最简配置:仅拉取当前分支
    "/Users/name/project-d"
)

使用方法

  1. 确保脚本具有执行权限:
    chmod +x auto-update-repos.sh
  2. 直接运行脚本:
    ./auto-update-repos.sh
  3. 脚本运行结束后会输出执行汇总。
⏰ 进阶:如何在 macOS 上设置定时自动运行 (Crontab)

你可以使用 crontab 让这个脚本每天自动运行(例如每天早上上班前)。

  1. 打开 Crontab 编辑器
    在终端中运行:

    crontab -e
  2. 添加定时任务
    进入编辑模式后添加一行。
    例如:每天早上 9:00 运行脚本,并将日志输出到 update.log 文件:

    0 9 * * * /Users/wuxh/Scripts/auto-update-repos.sh >> /Users/wuxh/Scripts/update.log 2>&1

    (注意:请务必使用脚本的绝对路径)

  3. 保存并退出

    • 如果默认编辑器是 Vim:按 Esc,输入 :wq 然后回车。
    • 如果是 Nano:按 Ctrl+O 回车保存,然后 Ctrl+X 退出。
  4. 验证任务
    运行 crontab -l 查看任务列表。

提示:如果脚本执行因权限问题失败(如 macOS Full Disk Access),可能需要在 "系统设置 > 隐私与安全性 > 完全磁盘访问权限" 中添加 /usr/sbin/cron

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment