背景与需求
在快节奏的开发生态中,及时追踪项目更新是一大痛点。本文将介绍一个轻量但强大的 Bash 脚本,它能自动检查多个 GitHub 仓库的提交,并利用 ZeroClaw AI 生成中文更新摘要。
作为开发者或技术管理者,你可能同时关注多个开源项目。手动刷 GitHub 不仅耗时,还容易遗漏重要更新。理想的监控工具应具备:
- 多仓库支持:一次配置,批量监控
- 增量检查:避免重复处理旧提交
- 智能总结:自动提炼提交信息的关键点
- 轻量部署:无需复杂依赖,适合服务器定时任务
scripts/github_monitor.sh 正是针对这些需求设计的解决方案。
脚本核心功能
仓库列表配置
脚本使用数组定义要监控的仓库:
REPOS=(
"xxx/yyy"
"uuu/vvv"
)
你可以自由增删,脚本会按顺序检查每个仓库。
状态持久化
脚本在同级目录维护一个 JSON 状态文件 .github_repos.json,记录每个仓库的最后一次检查到的 commit SHA:
{
"xxx/yyy": "...",
"uuu/vvv": "..."
}
这种设计实现增量监控:每次运行只拉取自上次检查以来的新提交。
GitHub API 调用
脚本使用 curl 直接调用 GitHub API:
- 无 Token 模式:适合公开仓库,但受限于每小时 60 次请求限制
- Token 模式:通过环境变量
GITHUB_TOKEN传递,大幅提升限额(公开仓库每小时 5000 次)
API 调用包含超时参数,避免网络阻塞:
curl -s --connect-timeout 10 --max-time 30 ...
时间戳增量策略
脚本的核心逻辑在 fetch_commits() 函数:
- 读取上次记录的 SHA
- 若为空(首次运行),只获取最新一条提交
- 若有上次 SHA,则获取该提交的时间戳,使用
since参数拉取之后的新提交 - 过滤掉可能被重复包含的
last_sha自身 - 更新状态文件为最新 SHA
这种策略在大多数情况下只需一次 API 调用,效率较高。
AI 智能总结
脚本最特别的功能是调用 ZeroClaw 生成中文更新摘要:
local prompt="
你是一个直接输出结果的工具。严禁输出任何思考、分析或解释过程。
严格限定于提交信息本身进行合理推断。严格遵循以下格式生成总结。
只输出最终总结,不输出任何冗余内容。输出语言使用中文。输出格式:
## 主要更新:
## 核心变更:
## 影响:
提交信息如下:
$commits_log
"
local summary_text=$(zeroclaw agent -m "$prompt" 2>/dev/null)
ZeroClaw 被限制在 60 秒内完成响应,并强制输出简洁的三段式总结。如果超时或失败,脚本会输出备用提示。
技术实现细节
依赖管理
脚本依赖两个命令行工具:
jq:JSON 解析,用于读取状态文件和 API 响应curl:HTTP 请求,访问 GitHub API
启动时会检查是否已安装,缺失则报错退出。
错误处理
脚本在多个环节进行防御性编程:
- API 返回非数组时提示错误并输出响应样例
- 无法解析最新 SHA 时跳过该仓库
jq更新状态文件失败时清理临时文件- AI 调用超时或失败时降级为提示信息
超时控制
curl:连接超时 10 秒,总时长不超过 30 秒zeroclaw agent:60 秒硬超时(timeout 60s)
这些参数可根据网络环境和 AI 响应速度调整。
部署与使用
安装依赖
# Ubuntu/Debian
apt-get install jq curl
# macOS
brew install jq curl
可选:配置 GitHub Token
为避免 API 限流,建议设置 GITHUB_TOKEN:
export GITHUB_TOKEN="ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# 可写入 ~/.bashrc 或系统服务环境变量
Token 只需 public_repo 权限即可。
运行脚本
bash scripts/github_monitor.sh
首次运行会创建状态文件并获取最新提交。
定时任务
配合 cron 实现自动监控。例如每天 UTC 08:00 运行并发送到 QQ:
0 8 * * * bash /root/.zeroclaw/workspace/scripts/github_monitor.sh
在 ZeroClaw 环境中,可使用 cron_add 工具将输出直接投递到 QQ 频道。
优化与扩展建议
解决超时问题
当前脚本在无 Token 或 ZeroClaw 响应慢时可能超时。可考虑:
- 配置 Token:最直接有效的方案
- 减少仓库数量:串行处理累积时间,可拆分多个定时任务
- 异步并行:使用
&后台执行或 GNU Parallel - 缓存 AI 响应:对相同提交内容复用总结
增强总结质量
- 调整 prompt 模板,指定更详细的输出结构
- 传入更多上下文(如文件变更行数、语言统计)
- 支持多语言输出(英文/中文)
输出多样化
- 将结果写入 Markdown 文件,生成静态更新日志页
- 集成到 Discord/Telegram/Slack Webhook
- 发送邮件通知
总结
完整的脚本如下:
#!/bin/bash
# ======================== 配置区 ========================
REPOS=(
"xxx/yyy"
"uuu/vvv"
)
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)
STATE_FILE="$SCRIPT_DIR/.github_repos.json"
# 请通过环境变量设置 GITHUB_TOKEN,例如:export GITHUB_TOKEN="ghp_xxx"
# export GITHUB_TOKEN=""
# API 每页最大条数(增量模式下一般一次足够)
PER_PAGE=50
# ======================== 初始化 ========================
if [ ! -f "$STATE_FILE" ]; then
echo "{}" > "$STATE_FILE"
fi
# ======================== 依赖检查 ========================
for cmd in jq curl; do
if ! command -v $cmd &> /dev/null; then
echo "错误:请先安装 $cmd"
exit 1
fi
done
# ======================== 辅助函数:获取提交时间 ========================
get_commit_date() {
local repo=$1
local sha=$2
local auth_header=()
if [ -n "$GITHUB_TOKEN" ]; then
auth_header=(-H "Authorization: token $GITHUB_TOKEN")
fi
local url="https://api.github.com/repos/$repo/commits/$sha"
curl -s --connect-timeout 10 --max-time 30 "${auth_header[@]}" "$url" | jq -r '.commit.committer.date // empty'
}
# ======================== 核心函数:增量获取新提交 ========================
fetch_commits() {
local repo=$1
# 安全读取上次记录的 SHA
local last_sha=$(jq -r --arg repo "$repo" '.[$repo] // ""' "$STATE_FILE")
echo "----"
echo "# 正在检查仓库: $repo "
local auth_header=()
if [ -n "$GITHUB_TOKEN" ]; then
auth_header=(-H "Authorization: token $GITHUB_TOKEN")
fi
local api_base="https://api.github.com/repos/$repo/commits"
local since_param=""
local commits_json=""
if [ -z "$last_sha" ]; then
# 首次运行:只取最新一条提交
echo "首次运行,获取最新提交..."
commits_json=$(curl -s --connect-timeout 10 --max-time 30 "${auth_header[@]}" "${api_base}?per_page=1")
else
# 获取上次提交的时间戳
local last_date=$(get_commit_date "$repo" "$last_sha")
if [ -z "$last_date" ]; then
echo "警告:无法获取上次提交 ($last_sha) 的时间戳,将退回到拉取最近 $PER_PAGE 条提交"
commits_json=$(curl -s --connect-timeout 10 --max-time 30 "${auth_header[@]}" "${api_base}?per_page=$PER_PAGE")
else
# URL 编码时间(ISO 8601 格式,直接将空格替换为 %20)
local encoded_date=$(echo "$last_date" | sed 's/ /%20/g')
since_param="?since=${encoded_date}&per_page=$PER_PAGE"
local local_date=$(TZ='Asia/Shanghai' date -d "$last_date" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || echo "$last_date")
echo "最后提交时间:$local_date"
commits_json=$(curl -s --connect-timeout 10 --max-time 30 "${auth_header[@]}" "${api_base}${since_param}")
fi
fi
# 验证返回数据是否为有效数组
if ! echo "$commits_json" | jq -e 'type == "array"' >/dev/null 2>&1; then
echo "错误:无法获取 $repo 的提交信息(API 限制或网络问题)"
echo "响应样例:$(echo "$commits_json" | head -c 200)"
return
fi
# 获取最新 SHA(数组第一个)
local latest_sha=$(echo "$commits_json" | jq -r '.[0].sha // empty')
if [ -z "$latest_sha" ] || [ "$latest_sha" = "null" ]; then
echo "错误:未能解析 $repo 的最新 SHA"
return
fi
# 检查是否有新提交
if [ "$latest_sha" = "$last_sha" ]; then
echo "已是最新版本。"
return
fi
# ------------------ 提取新提交日志 ------------------
local commits_log=""
if [ -z "$last_sha" ]; then
# 首次运行:只展示最新一条
commits_log=$(echo "$commits_json" | jq -r '.[0] | "\(.sha[0:7]) \(.commit.message)"')
else
# 过滤掉 last_sha 自身(since 参数可能包含该提交),并输出所有新提交
commits_log=$(echo "$commits_json" | jq -r --arg last "$last_sha" '
.[] | select(.sha != $last) | "\(.sha[0:7]) \(.commit.message)"
')
fi
if [ -z "$commits_log" ]; then
echo "无有效新提交记录(可能时间戳精度问题或已处理过)。"
# 仍然更新状态文件到最新 SHA,避免重复检查
else
# 可选:限制输出行数,防止 AI 过载(这里保留全部新提交,可根据需要取消注释)
# commits_log=$(echo "$commits_log" | head -n 20)
echo "发现新提交,正在生成总结:"
#echo "$commits_log" | while IFS= read -r line; do echo " $line"; done
fi
# ------------------ AI 总结 ------------------
if [ -n "$commits_log" ]; then
local prompt="
你是一个直接输出结果的工具。严禁输出任何思考、分析或解释过程。严格限定于提交信息本身进行合理推断。严格遵循以下格式生成总结。只输出最终总结,不输出任何冗余内容。输出语言使用中文。输出格式:
### 主要更新
### 核心变更
### 影响
提交信息如下:
$commits_log
"
# 调用 AI 代理
local summary_text=$(/root/.cargo/bin/zeroclaw agent -m "$prompt" 2>/dev/null)
if [ $? -ne 0 ] || [ -z "$summary_text" ]; then
summary_text="⚠️ AI 总结生成超时或失败"
fi
echo "## $repo 更新摘要"
echo "$summary_text"
fi
# ------------------ 安全更新状态文件 ------------------
local tmp_file=$(mktemp)
if jq --arg repo "$repo" --arg sha "$latest_sha" '.[$repo] = $sha' "$STATE_FILE" > "$tmp_file" 2>/dev/null; then
mv "$tmp_file" "$STATE_FILE"
echo "已更新状态文件:$repo -> ${latest_sha:0:7}"
else
echo "错误:无法更新状态文件"
rm -f "$tmp_file"
fi
}
# ======================== 主循环 ========================
for repo in "${REPOS[@]}"; do
fetch_commits "$repo"
done
github_monitor.sh 是一个简洁而实用的自动化工具,它结合了 GitHub API 的增量查询和 ZeroClaw AI 的智能总结,为开发者提供了“设置后忘记”的仓库监控体验。
核心优势:
- ✅ 纯 Bash 实现,易于理解和修改
- ✅ 增量检查,避免重复处理
- ✅ AI 自动生成中文摘要,降低阅读成本
- ✅ 可轻松集成到定时任务和消息通知
适用场景:
- 个人开发者跟踪兴趣项目
- 技术团队监控依赖库更新
- 开源维护者收集社区动态
如果你也在寻找轻量级的 GitHub 监控方案,不妨试试这个脚本,并根据自己的需求进行定制。

