626 lines
18 KiB
Bash
Executable File
626 lines
18 KiB
Bash
Executable File
#!/bin/bash
|
||
# 《末日重生》项目Git版本管理脚本
|
||
# 提供自动提交、版本标签、定时同步功能
|
||
|
||
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||
LOG_FILE="$PROJECT_DIR/logs/git_version.log"
|
||
CONFIG_FILE="$PROJECT_DIR/config/version_config.json"
|
||
|
||
# 颜色输出
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# 初始化日志和配置
|
||
init() {
|
||
mkdir -p "$(dirname "$LOG_FILE")"
|
||
mkdir -p "$(dirname "$CONFIG_FILE")"
|
||
|
||
if [ ! -f "$CONFIG_FILE" ]; then
|
||
cat > "$CONFIG_FILE" << EOF
|
||
{
|
||
"auto_commit": true,
|
||
"commit_pattern": "更新: {date} {time}",
|
||
"commit_threshold": 3,
|
||
"auto_tag": true,
|
||
"tag_pattern": "v{version}",
|
||
"tag_milestones": [5, 10, 20, 50, 100],
|
||
"sync_enabled": true,
|
||
"sync_schedule": "*/30 * * * *",
|
||
"backup_enabled": true,
|
||
"backup_retention": 7,
|
||
"notifications": {
|
||
"on_success": true,
|
||
"on_failure": true
|
||
}
|
||
}
|
||
EOF
|
||
fi
|
||
}
|
||
|
||
# 日志函数
|
||
log() {
|
||
local level="$1"
|
||
local message="$2"
|
||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||
|
||
case $level in
|
||
"INFO") color=$GREEN ;;
|
||
"WARN") color=$YELLOW ;;
|
||
"ERROR") color=$RED ;;
|
||
*) color=$NC ;;
|
||
esac
|
||
|
||
echo -e "${color}[$timestamp] [$level] $message${NC}"
|
||
echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
|
||
}
|
||
|
||
# 检查Git状态
|
||
check_git_status() {
|
||
log "INFO" "检查Git状态..."
|
||
|
||
cd "$PROJECT_DIR"
|
||
|
||
# 检查是否有未提交的更改
|
||
if [ -n "$(git status --porcelain)" ]; then
|
||
changed_files=$(git status --porcelain | wc -l)
|
||
log "INFO" "检测到 $changed_files 个未提交的文件"
|
||
|
||
# 显示更改摘要
|
||
echo "📝 更改摘要:"
|
||
git status --short
|
||
echo ""
|
||
|
||
return 0 # 有更改
|
||
else
|
||
log "INFO" "没有未提交的更改"
|
||
return 1 # 没有更改
|
||
fi
|
||
}
|
||
|
||
# 自动提交更改
|
||
auto_commit() {
|
||
local message="$1"
|
||
|
||
if [ -z "$message" ]; then
|
||
local current_date=$(date '+%Y年%m月%d日')
|
||
local current_time=$(date '+%H:%M:%S')
|
||
message="更新: $current_date $current_time"
|
||
fi
|
||
|
||
log "INFO" "自动提交更改: $message"
|
||
|
||
cd "$PROJECT_DIR"
|
||
|
||
# 添加所有更改
|
||
git add .
|
||
|
||
# 提交
|
||
if git commit -m "$message" > /dev/null 2>&1; then
|
||
local commit_hash=$(git rev-parse --short HEAD)
|
||
log "INFO" "✅ 提交成功 (commit: $commit_hash)"
|
||
echo "提交信息: $message"
|
||
echo "提交哈希: $commit_hash"
|
||
return 0
|
||
else
|
||
log "ERROR" "❌ 提交失败"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# 创建版本标签
|
||
create_version_tag() {
|
||
local tag_name="$1"
|
||
local tag_message="$2"
|
||
|
||
if [ -z "$tag_name" ]; then
|
||
# 自动生成标签名
|
||
local current_version=$(git tag | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -1)
|
||
|
||
if [ -z "$current_version" ]; then
|
||
current_version="v0.0.0"
|
||
fi
|
||
|
||
# 递增版本号
|
||
local major=$(echo "$current_version" | cut -d. -f1 | tr -d 'v')
|
||
local minor=$(echo "$current_version" | cut -d. -f2)
|
||
local patch=$(echo "$current_version" | cut -d. -f3)
|
||
|
||
patch=$((patch + 1))
|
||
|
||
# 每10个小版本升级一个中版本
|
||
if [ $patch -ge 10 ]; then
|
||
patch=0
|
||
minor=$((minor + 1))
|
||
fi
|
||
|
||
# 每10个中版本升级一个大版本
|
||
if [ $minor -ge 10 ]; then
|
||
minor=0
|
||
major=$((major + 1))
|
||
fi
|
||
|
||
tag_name="v${major}.${minor}.${patch}"
|
||
fi
|
||
|
||
if [ -z "$tag_message" ]; then
|
||
local chapter_count=$(find "$PROJECT_DIR/chapters" -name "*.md" | wc -l)
|
||
local total_words=0
|
||
|
||
for chapter in "$PROJECT_DIR/chapters"/*.md; do
|
||
if [ -f "$chapter" ]; then
|
||
words=$(wc -w < "$chapter" 2>/dev/null || echo 0)
|
||
total_words=$((total_words + words))
|
||
fi
|
||
done
|
||
|
||
tag_message="版本 ${tag_name} | 章节: ${chapter_count}章 | 字数: ${total_words}字"
|
||
fi
|
||
|
||
log "INFO" "创建版本标签: $tag_name"
|
||
|
||
if git tag -a "$tag_name" -m "$tag_message" > /dev/null 2>&1; then
|
||
log "INFO" "✅ 标签创建成功: $tag_name"
|
||
echo "标签名称: $tag_name"
|
||
echo "标签描述: $tag_message"
|
||
return 0
|
||
else
|
||
log "ERROR" "❌ 标签创建失败"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# 同步到远程仓库
|
||
sync_to_remote() {
|
||
local force="$1"
|
||
|
||
log "INFO" "同步到远程仓库..."
|
||
|
||
cd "$PROJECT_DIR"
|
||
|
||
# 检查远程仓库
|
||
if ! git remote get-url origin > /dev/null 2>&1; then
|
||
log "ERROR" "❌ 未配置远程仓库"
|
||
return 1
|
||
fi
|
||
|
||
# 获取远程仓库信息
|
||
local remote_url=$(git remote get-url origin)
|
||
log "INFO" "远程仓库: $(echo $remote_url | sed 's|https://.*@||')"
|
||
|
||
# 拉取最新更改
|
||
log "INFO" "拉取远程更改..."
|
||
if ! git pull --rebase origin master 2>&1 | grep -q "Already up to date"; then
|
||
log "INFO" "✅ 已更新本地仓库"
|
||
fi
|
||
|
||
# 推送更改
|
||
log "INFO" "推送到远程仓库..."
|
||
if [ "$force" = "true" ]; then
|
||
if git push origin master --tags --force 2>&1; then
|
||
log "INFO" "✅ 强制推送成功"
|
||
else
|
||
log "ERROR" "❌ 推送失败"
|
||
return 1
|
||
fi
|
||
else
|
||
if git push origin master --tags 2>&1; then
|
||
log "INFO" "✅ 推送成功"
|
||
else
|
||
log "WARN" "⚠️ 推送失败,尝试强制推送..."
|
||
if git push origin master --tags --force 2>&1; then
|
||
log "INFO" "✅ 强制推送成功"
|
||
else
|
||
log "ERROR" "❌ 强制推送失败"
|
||
return 1
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
# 显示同步结果
|
||
local current_branch=$(git branch --show-current)
|
||
local latest_commit=$(git log -1 --format="%h - %s" 2>/dev/null)
|
||
local tag_count=$(git tag | wc -l)
|
||
|
||
echo ""
|
||
echo "📊 同步完成报告"
|
||
echo "├─ 分支: $current_branch"
|
||
echo "├─ 最新提交: $latest_commit"
|
||
echo "├─ 版本标签: $tag_count 个"
|
||
echo "└─ 远程仓库: $(echo $remote_url | sed 's|https://.*@||')"
|
||
|
||
return 0
|
||
}
|
||
|
||
# 自动备份
|
||
create_backup() {
|
||
local backup_type="$1"
|
||
|
||
log "INFO" "创建项目备份..."
|
||
|
||
local backup_dir="$PROJECT_DIR/backups"
|
||
local timestamp=$(date '+%Y%m%d_%H%M%S')
|
||
|
||
mkdir -p "$backup_dir"
|
||
|
||
case $backup_type in
|
||
"full")
|
||
# 完整备份
|
||
local backup_file="$backup_dir/full_backup_$timestamp.tar.gz"
|
||
tar -czf "$backup_file" -C "$PROJECT_DIR" .
|
||
log "INFO" "✅ 完整备份创建: $(basename $backup_file)"
|
||
;;
|
||
"git")
|
||
# Git包备份
|
||
local backup_file="$backup_dir/git_bundle_$timestamp.bundle"
|
||
git bundle create "$backup_file" --all
|
||
log "INFO" "✅ Git包备份创建: $(basename $backup_file)"
|
||
;;
|
||
"chapters")
|
||
# 章节备份
|
||
local backup_file="$backup_dir/chapters_$timestamp.tar.gz"
|
||
tar -czf "$backup_file" -C "$PROJECT_DIR" chapters/
|
||
log "INFO" "✅ 章节备份创建: $(basename $backup_file)"
|
||
;;
|
||
*)
|
||
# 默认备份
|
||
local backup_file="$backup_dir/backup_$timestamp.tar.gz"
|
||
tar -czf "$backup_file" -C "$PROJECT_DIR" chapters/ outlines/ assets/
|
||
log "INFO" "✅ 默认备份创建: $(basename $backup_file)"
|
||
;;
|
||
esac
|
||
|
||
# 清理旧备份
|
||
local retention_days=7
|
||
find "$backup_dir" -name "*.tar.gz" -mtime +$retention_days -delete 2>/dev/null
|
||
find "$backup_dir" -name "*.bundle" -mtime +$retention_days -delete 2>/dev/null
|
||
|
||
echo "备份文件: $backup_file"
|
||
echo "备份大小: $(du -h "$backup_file" | cut -f1)"
|
||
|
||
return 0
|
||
}
|
||
|
||
# 项目状态报告
|
||
generate_status_report() {
|
||
log "INFO" "生成项目状态报告..."
|
||
|
||
cd "$PROJECT_DIR"
|
||
|
||
local report_file="$PROJECT_DIR/progress/status_report_$(date '+%Y%m%d').md"
|
||
mkdir -p "$(dirname "$report_file")"
|
||
|
||
# 收集数据
|
||
local chapter_count=$(find chapters -name "*.md" | wc -l)
|
||
local total_words=0
|
||
local latest_chapter=""
|
||
local latest_chapter_time=""
|
||
|
||
for chapter in chapters/*.md; do
|
||
if [ -f "$chapter" ]; then
|
||
words=$(wc -w < "$chapter" 2>/dev/null || echo 0)
|
||
total_words=$((total_words + words))
|
||
|
||
# 找到最新章节
|
||
chapter_time=$(stat -c %Y "$chapter" 2>/dev/null || echo 0)
|
||
if [ -z "$latest_chapter_time" ] || [ $chapter_time -gt $latest_chapter_time ]; then
|
||
latest_chapter_time=$chapter_time
|
||
latest_chapter=$(basename "$chapter" .md)
|
||
fi
|
||
fi
|
||
done
|
||
|
||
local commit_count=$(git rev-list --count HEAD 2>/dev/null || echo 0)
|
||
local latest_commit=$(git log -1 --format="%h - %s (%ad)" --date=short 2>/dev/null || echo "无")
|
||
local tag_count=$(git tag | wc -l)
|
||
local latest_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "无")
|
||
|
||
# 生成报告
|
||
cat > "$report_file" << EOF
|
||
# 《末日重生》项目状态报告
|
||
|
||
## 报告时间
|
||
$(date '+%Y年%m月%d日 %H:%M:%S')
|
||
|
||
## 创作进度
|
||
- **总章节**: ${chapter_count} 章
|
||
- **总字数**: ${total_words} 字
|
||
- **最新章节**: ${latest_chapter}
|
||
- **平均每章字数**: $((total_words / chapter_count)) 字
|
||
|
||
## 版本管理
|
||
- **提交次数**: ${commit_count} 次
|
||
- **最新提交**: ${latest_commit}
|
||
- **版本标签**: ${tag_count} 个
|
||
- **最新版本**: ${latest_tag}
|
||
|
||
## 番茄平台适配
|
||
### 字数要求
|
||
- 标准章节字数: 2500-3500字
|
||
- 当前平均: $((total_words / chapter_count)) 字
|
||
- 状态: $(if [ $((total_words / chapter_count)) -ge 2000 ] && [ $((total_words / chapter_count)) -le 3500 ]; then echo "✅ 符合标准"; else echo "⚠️ 需要调整"; fi)
|
||
|
||
### 更新要求
|
||
- 日更全勤要求: 4000字/天
|
||
- 当前总字数: ${total_words} 字
|
||
- 相当于: $((total_words / 4000)) 天的全勤更新量
|
||
|
||
## Git状态
|
||
\`\`\`bash
|
||
$(git status --short 2>/dev/null || echo "无未提交更改")
|
||
\`\`\`
|
||
|
||
## 下一步计划
|
||
1. [ ] 继续创作第 $(($chapter_count + 1)) 章
|
||
2. [ ] 检查并优化现有章节
|
||
3. [ ] 更新项目大纲和设定
|
||
4. [ ] 同步到远程仓库
|
||
|
||
## 健康检查
|
||
- [$(if [ $chapter_count -gt 0 ]; then echo "x"; else echo " "; fi)] 章节文件正常
|
||
- [$(if [ -d ".git" ]; then echo "x"; else echo " "; fi)] Git仓库正常
|
||
- [$(if git remote get-url origin >/dev/null 2>&1; then echo "x"; else echo " "; fi)] 远程仓库配置
|
||
- [$(if [ -f "$report_file" ]; then echo "x"; else echo " "; fi)] 报告生成正常
|
||
|
||
---
|
||
*报告自动生成于 $(date '+%Y-%m-%d %H:%M:%S')*
|
||
EOF
|
||
|
||
log "INFO" "✅ 状态报告生成: $(basename $report_file)"
|
||
echo "报告文件: $report_file"
|
||
|
||
return 0
|
||
}
|
||
|
||
# 定时同步任务
|
||
setup_cron_job() {
|
||
local schedule="$1"
|
||
|
||
if [ -z "$schedule" ]; then
|
||
schedule="*/30 * * * *" # 每30分钟
|
||
fi
|
||
|
||
log "INFO" "设置定时同步任务: $schedule"
|
||
|
||
# 创建定时任务脚本
|
||
local cron_script="/tmp/末日重生_定时同步.sh"
|
||
|
||
cat > "$cron_script" << 'CRON_EOF'
|
||
#!/bin/bash
|
||
# 《末日重生》定时同步脚本
|
||
|
||
PROJECT_DIR="/root/.openclaw/workspace/projects/末日重生_囤货"
|
||
LOG_FILE="/tmp/末日重生_同步日志.log"
|
||
|
||
log() {
|
||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
|
||
}
|
||
|
||
log "INFO" "开始定时同步任务"
|
||
|
||
cd "$PROJECT_DIR"
|
||
|
||
# 检查是否有未提交的更改
|
||
if [ -n "$(git status --porcelain)" ]; then
|
||
log "INFO" "检测到未提交的更改,自动提交..."
|
||
|
||
# 自动提交
|
||
commit_message="定时更新: $(date '+%Y年%m月%d日 %H:%M:%S')"
|
||
git add .
|
||
if git commit -m "$commit_message" >/dev/null 2>&1; then
|
||
commit_hash=$(git rev-parse --short HEAD)
|
||
log "INFO" "✅ 自动提交成功: $commit_hash"
|
||
else
|
||
log "ERROR" "❌ 自动提交失败"
|
||
fi
|
||
fi
|
||
|
||
# 同步到远程
|
||
log "INFO" "同步到远程仓库..."
|
||
if git pull --rebase origin master >/dev/null 2>&1 && git push origin master >/dev/null 2>&1; then
|
||
log "INFO" "✅ 同步成功"
|
||
else
|
||
log "WARN" "⚠️ 同步失败,下次重试"
|
||
fi
|
||
|
||
# 创建每日备份(只在特定时间)
|
||
if [ "$(date '+%H')" = "03" ]; then # 凌晨3点
|
||
log "INFO" "创建每日备份..."
|
||
tar -czf "/tmp/末日重生_备份_$(date '+%Y%m%d').tar.gz" -C "$PROJECT_DIR" .
|
||
log "INFO" "✅ 备份创建完成"
|
||
fi
|
||
|
||
log "INFO" "定时同步任务完成"
|
||
CRON_EOF
|
||
|
||
chmod +x "$cron_script"
|
||
|
||
# 添加cron任务
|
||
(crontab -l 2>/dev/null | grep -v "$cron_script"; echo "$schedule $cron_script") | crontab -
|
||
|
||
log "INFO" "✅ 定时任务设置完成"
|
||
echo "定时任务: $schedule"
|
||
echo "任务脚本: $cron_script"
|
||
|
||
return 0
|
||
}
|
||
|
||
# 主菜单
|
||
show_menu() {
|
||
echo ""
|
||
echo "📚 《末日重生》项目版本管理系统"
|
||
echo "================================="
|
||
echo ""
|
||
echo "1. 🔍 检查项目状态"
|
||
echo "2. 📝 自动提交更改"
|
||
echo "3. 🏷️ 创建版本标签"
|
||
echo "4. 🔄 同步到远程仓库"
|
||
echo "5. 💾 创建项目备份"
|
||
echo "6. 📊 生成状态报告"
|
||
echo "7. ⏰ 设置定时同步"
|
||
echo "8. 🚀 一键全流程"
|
||
echo "9. 📋 显示帮助"
|
||
echo "0. ❌ 退出"
|
||
echo ""
|
||
echo "================================="
|
||
}
|
||
|
||
# 一键全流程
|
||
full_workflow() {
|
||
log "INFO" "开始一键全流程..."
|
||
|
||
echo "🚀 执行一键全流程"
|
||
echo "----------------"
|
||
|
||
# 1. 检查状态
|
||
if check_git_status; then
|
||
echo "✅ 步骤1: 检查状态完成"
|
||
else
|
||
echo "ℹ️ 步骤1: 无未提交更改"
|
||
fi
|
||
|
||
# 2. 自动提交
|
||
if auto_commit "一键更新: $(date '+%Y年%m月%d日 %H:%M:%S')"; then
|
||
echo "✅ 步骤2: 自动提交完成"
|
||
else
|
||
echo "⚠️ 步骤2: 提交跳过"
|
||
fi
|
||
|
||
# 3. 检查是否需要创建标签
|
||
local commit_count=$(git rev-list --count HEAD 2>/dev/null || echo 0)
|
||
if [ $((commit_count % 10)) -eq 0 ]; then
|
||
if create_version_tag; then
|
||
echo "✅ 步骤3: 版本标签创建"
|
||
else
|
||
echo "⚠️ 步骤3: 标签跳过"
|
||
fi
|
||
fi
|
||
|
||
# 4. 同步到远程
|
||
if sync_to_remote; then
|
||
echo "✅ 步骤4: 远程同步完成"
|
||
else
|
||
echo "❌ 步骤4: 同步失败"
|
||
fi
|
||
|
||
# 5. 生成报告
|
||
if generate_status_report; then
|
||
echo "✅ 步骤5: 状态报告生成"
|
||
fi
|
||
|
||
log "INFO" "一键全流程完成"
|
||
echo "🎉 全流程执行完毕!"
|
||
}
|
||
|
||
# 显示帮助
|
||
show_help() {
|
||
echo ""
|
||
echo "📖 《末日重生》Git版本管理工具使用说明"
|
||
echo "========================================"
|
||
echo ""
|
||
echo "主要功能:"
|
||
echo " 🔍 检查状态 - 检查Git状态和未提交更改"
|
||
echo " 📝 自动提交 - 自动提交所有更改到本地仓库"
|
||
echo " 🏷️ 版本标签 - 创建版本标签,记录重要里程碑"
|
||
echo " 🔄 远程同步 - 同步到Gitea远程仓库"
|
||
echo " 💾 项目备份 - 创建项目备份文件"
|
||
echo " 📊 状态报告 - 生成详细的项目状态报告"
|
||
echo " ⏰ 定时同步 - 设置定时自动同步任务"
|
||
echo " 🚀 一键流程 - 执行完整的版本管理流程"
|
||
echo ""
|
||
echo "使用方式:"
|
||
echo " ./git_version_manager.sh [选项]"
|
||
echo ""
|
||
echo "选项:"
|
||
echo " status 检查项目状态"
|
||
echo " commit 自动提交更改"
|
||
echo " tag 创建版本标签"
|
||
echo " sync 同步到远程"
|
||
echo " backup 创建备份"
|
||
echo " report 生成报告"
|
||
echo " cron 设置定时任务"
|
||
echo " workflow 执行一键流程"
|
||
echo " menu 显示交互菜单"
|
||
echo " help 显示帮助"
|
||
echo ""
|
||
echo "示例:"
|
||
echo " ./git_version_manager.sh status"
|
||
echo " ./git_version_manager.sh workflow"
|
||
echo " ./git_version_manager.sh menu"
|
||
echo ""
|
||
}
|
||
|
||
# 主函数
|
||
main() {
|
||
init
|
||
|
||
case "$1" in
|
||
"status")
|
||
check_git_status
|
||
;;
|
||
"commit")
|
||
auto_commit "$2"
|
||
;;
|
||
"tag")
|
||
create_version_tag "$2" "$3"
|
||
;;
|
||
"sync")
|
||
sync_to_remote "$2"
|
||
;;
|
||
"backup")
|
||
create_backup "$2"
|
||
;;
|
||
"report")
|
||
generate_status_report
|
||
;;
|
||
"cron")
|
||
setup_cron_job "$2"
|
||
;;
|
||
"workflow"|"auto")
|
||
full_workflow
|
||
;;
|
||
"menu")
|
||
while true; do
|
||
show_menu
|
||
echo "请选择操作 (0-9): "
|
||
read choice
|
||
|
||
case $choice in
|
||
1) check_git_status ;;
|
||
2) auto_commit ;;
|
||
3) create_version_tag ;;
|
||
4) sync_to_remote ;;
|
||
5) create_backup ;;
|
||
6) generate_status_report ;;
|
||
7) setup_cron_job ;;
|
||
8) full_workflow ;;
|
||
9) show_help ;;
|
||
0)
|
||
echo "再见!"
|
||
exit 0
|
||
;;
|
||
*)
|
||
echo "❌ 无效选择"
|
||
;;
|
||
esac
|
||
|
||
echo ""
|
||
echo "按回车键继续..."
|
||
read
|
||
done
|
||
;;
|
||
"help"|"--help"|"-h")
|
||
show_help
|
||
;;
|
||
*)
|
||
echo "使用: $0 [命令]"
|
||
echo "可用命令: status, commit, tag, sync, backup, report, cron, workflow, menu, help"
|
||
exit 1
|
||
;;
|
||
esac
|
||
}
|
||
|
||
# 运行主函数
|
||
main "$@" |