├── assets ├── run.webp └── mail.webp ├── feishu_notify.sh ├── LICENSE ├── config.sh ├── mail.sh ├── main.sh ├── mirror.sh └── README.md /assets/run.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/songtianlun/mirrorGit/HEAD/assets/run.webp -------------------------------------------------------------------------------- /assets/mail.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/songtianlun/mirrorGit/HEAD/assets/mail.webp -------------------------------------------------------------------------------- /feishu_notify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 参数获取 4 | WEBHOOK_URL="$1" 5 | TITLE="$2" 6 | CONTENT="$3" 7 | 8 | # 飞书通知 9 | send_feishu_notification() { 10 | local message=$(jq -n \ 11 | --arg title "$TITLE" \ 12 | --arg text "$CONTENT" \ 13 | '{ 14 | msg_type: "post", 15 | content: { 16 | post: { 17 | zh_cn: { 18 | title: $title, 19 | content: [[{ 20 | tag: "text", 21 | text: $text 22 | }]] 23 | } 24 | } 25 | } 26 | }' 27 | ) 28 | curl -s -X POST "$WEBHOOK_URL" -H "Content-Type: application/json" -d "$message" 29 | } 30 | 31 | # 主函数 32 | main() { 33 | if [ -z "$WEBHOOK_URL" ] || [ -z "$TITLE" ] || [ -z "$CONTENT" ]; then 34 | echo "错误: 缺少必要的飞书通知参数" 35 | exit 1 36 | fi 37 | send_feishu_notification 38 | } 39 | 40 | main "$@" 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 TianLun Song 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # GitHub 配置 4 | GITHUB_USER=${GITHUB_USER:-"default-github-username"} 5 | GITHUB_TOKEN=${GITHUB_TOKEN:-""} 6 | 7 | # Gitea 配置 8 | GITEA_URL=${GITEA_URL:-"https://your-gitea-instance"} 9 | GITEA_USER=${GITEA_USER:-"default-gitea-username"} 10 | GITEA_TOKEN=${GITEA_TOKEN:-"default-gitea-token"} 11 | 12 | # 工作目录配置 13 | WORK_DIR=${WORK_DIR:-"/tmp/github-mirror"} 14 | LOG_DIR=${LOG_DIR:-"$WORK_DIR/logs"} 15 | 16 | # 邮件配置 17 | ENABLE_MAIL=${ENABLE_MAIL:-"false"} 18 | SMTP_SERVER=${SMTP_SERVER:-""} 19 | SMTP_PORT=${SMTP_PORT:-"587"} 20 | SMTP_USER=${SMTP_USER:-""} 21 | SMTP_PASS=${SMTP_PASS:-""} 22 | MAIL_TO=${MAIL_TO:-""} 23 | MAIL_FROM=${MAIL_FROM:-"$SMTP_USER"} 24 | 25 | # 飞书通知配置 26 | ENABLE_FEISHU=${ENABLE_FEISHU:-"false"} 27 | FEISHU_WEBHOOK_URL=${FEISHU_WEBHOOK_URL:-""} 28 | 29 | # 跳过的仓库 30 | SKIP_REPOS=${SKIP_REPOS:-"archive,AutoApiSecret, \ 31 | backup-openbilibili-go-common, \ 32 | carrot,ChatGLM-6B,dokploy,hub-mirror, \ 33 | Download-macOS, \ 34 | songtianlun,songtianlun.github.io"} 35 | 36 | # 系统配置 37 | LOG_FILE="$LOG_DIR/mirror-$(date '+%Y%m%d-%H%M%S').log" 38 | STATS_FILE="$LOG_DIR/sync_stats-$(date '+%Y%m%d-%H%M%S').json" 39 | -------------------------------------------------------------------------------- /mail.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 参数获取 4 | SMTP_SERVER="$1" 5 | SMTP_PORT="$2" 6 | SMTP_USER="$3" 7 | SMTP_PASS="$4" 8 | MAIL_TO="$5" 9 | MAIL_FROM="$6" 10 | SUBJECT="$7" 11 | BODY="$8" 12 | 13 | # 发送邮件 14 | send_mail() { 15 | local email_content="Subject: $SUBJECT 16 | From: $MAIL_FROM 17 | To: $MAIL_TO 18 | Content-Type: text/plain; charset=UTF-8 19 | Date: $(date -R) 20 | 21 | $BODY" 22 | 23 | if [ "$SMTP_PORT" == 465 ]; then 24 | curl -s --url "smtps://$SMTP_SERVER:$SMTP_PORT" \ 25 | --mail-from "$MAIL_FROM" \ 26 | --mail-rcpt "$MAIL_TO" \ 27 | --upload-file - \ 28 | --ssl-reqd \ 29 | --user "$SMTP_USER:$SMTP_PASS" \ 30 | <<< "$email_content" 31 | else 32 | curl -s --url "smtp://$SMTP_SERVER:$SMTP_PORT" \ 33 | --mail-from "$MAIL_FROM" \ 34 | --mail-rcpt "$MAIL_TO" \ 35 | --upload-file - \ 36 | --ssl-reqd \ 37 | --user "$SMTP_USER:$SMTP_PASS" \ 38 | <<< "$email_content" 39 | fi 40 | } 41 | 42 | # 主函数 43 | main() { 44 | # 验证必要参数 45 | if [ -z "$SMTP_SERVER" ] || [ -z "$SMTP_USER" ] || [ -z "$SMTP_PASS" ] || [ -z "$MAIL_TO" ]; then 46 | echo "错误: 缺少必要的邮件配置" 47 | exit 1 48 | fi 49 | 50 | send_mail 51 | } 52 | 53 | main "$@" -------------------------------------------------------------------------------- /main.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 获取脚本所在目录的绝对路径 4 | SCRIPT_DIR=$(readlink -f $(dirname $0)) 5 | 6 | # 加载配置 7 | source "$SCRIPT_DIR/config.sh" 8 | 9 | # 颜色定义 10 | RED='\033[0;31m' 11 | GREEN='\033[0;32m' 12 | YELLOW='\033[1;33m' 13 | NC='\033[0m' 14 | 15 | # 初始化日志 16 | init_logging() { 17 | mkdir -p "$LOG_DIR" 18 | exec 1> >(tee -a "$LOG_FILE") 19 | exec 2> >(tee -a "$LOG_FILE" >&2) 20 | } 21 | 22 | # 日志函数 23 | log() { 24 | local message="$1" 25 | local timestamp=$(date '+%Y-%m-%d %H:%M:%S') 26 | echo -e "$timestamp $message" 27 | } 28 | 29 | # 检查必要的命令 30 | check_requirements() { 31 | command -v git >/dev/null 2>&1 || error_exit "需要安装 git" 32 | command -v curl >/dev/null 2>&1 || error_exit "需要安装 curl" 33 | command -v jq >/dev/null 2>&1 || error_exit "需要安装 jq" 34 | } 35 | 36 | # 主函数 37 | main() { 38 | init_logging 39 | check_requirements 40 | 41 | log "开始同步处理..." 42 | 43 | # 调用 mirror.sh 进行同步 44 | bash "$SCRIPT_DIR/mirror.sh" \ 45 | "$GITHUB_USER" \ 46 | "$GITHUB_TOKEN" \ 47 | "$GITEA_URL" \ 48 | "$GITEA_USER" \ 49 | "$GITEA_TOKEN" \ 50 | "$WORK_DIR" \ 51 | "$SKIP_REPOS" \ 52 | "$STATS_FILE" 53 | 54 | mirror_exit_code=$? 55 | 56 | # 准备邮件内容 57 | notice_subject="GitHub 同步$([ $mirror_exit_code -eq 0 ] && echo "成功" || echo "失败") - $(date '+%Y-%m-%d')" 58 | summary="" 59 | 60 | if [ -f "$STATS_FILE" ]; then 61 | stats=$(cat "$STATS_FILE") 62 | summary="GitHub to Gitea 同步报告 63 | 64 | 开始时间: $(echo "$stats" | jq -r '.start_time') 65 | 结束时间: $(echo "$stats" | jq -r '.end_time') 66 | 同步状态: $([ $mirror_exit_code -eq 0 ] && echo "成功" || echo "失败") 67 | 68 | 统计信息: 69 | - 总仓库数: $(echo "$stats" | jq -r '.total_repos') 70 | - 处理数量: $(echo "$stats" | jq -r '.processed') 71 | - 成功数量: $(echo "$stats" | jq -r '.success') 72 | - 失败数量: $(echo "$stats" | jq -r '.failed') 73 | - 跳过数量: $(echo "$stats" | jq -r '.skipped') 74 | 75 | 跳过的仓库: 76 | $(echo "$stats" | jq -r '.details.skipped_repos[]' | sed 's/^/- /') 77 | 78 | 失败的仓库: 79 | $(echo "$stats" | jq -r '.details.failed_repos[]' | sed 's/^/- /') 80 | 81 | 成功的仓库: 82 | $(echo "$stats" | jq -r '.details.success_repos[]' | sed 's/^/- /') 83 | " 84 | 85 | else 86 | summary="无法获取同步统计信息" 87 | fi 88 | 89 | notice_content="$summary 90 | 91 | 详细日志 (最后 50 行): 92 | $(tail -n 50 "$LOG_FILE") 93 | 94 | 全部日志: 95 | $(cat "$LOG_FILE") 96 | " 97 | 98 | # 如果启用了邮件通知,调用 mail.sh 99 | if [ "$ENABLE_MAIL" = "true" ]; then 100 | bash "$SCRIPT_DIR/mail.sh" \ 101 | "$SMTP_SERVER" \ 102 | "$SMTP_PORT" \ 103 | "$SMTP_USER" \ 104 | "$SMTP_PASS" \ 105 | "$MAIL_TO" \ 106 | "$MAIL_FROM" \ 107 | "$notice_subject" \ 108 | "$notice_content" 109 | fi 110 | 111 | # 如果启用了飞书通知,调用 feishu_notify.sh 112 | if [ "$ENABLE_FEISHU" = "true" ]; then 113 | bash "$SCRIPT_DIR/feishu_notify.sh" \ 114 | "$FEISHU_WEBHOOK_URL" \ 115 | "$notice_subject" \ 116 | "$notice_content" 117 | fi 118 | 119 | 120 | # 清理工作目录 121 | [ -d "$WORK_DIR" ] && rm -rf "$WORK_DIR" 122 | 123 | exit $mirror_exit_code 124 | } 125 | 126 | main "$@" 127 | -------------------------------------------------------------------------------- /mirror.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 参数获取 4 | GITHUB_USER="$1" 5 | GITHUB_TOKEN="$2" 6 | GITEA_URL="$3" 7 | GITEA_USER="$4" 8 | GITEA_TOKEN="$5" 9 | WORK_DIR="$6" 10 | SKIP_REPOS="$7" 11 | STATS_FILE="$8" 12 | 13 | # 初始化统计 14 | init_stats() { 15 | cat > "$STATS_FILE" << EOF 16 | { 17 | "total_repos": 0, 18 | "processed": 0, 19 | "skipped": 0, 20 | "success": 0, 21 | "failed": 0, 22 | "start_time": "$(date '+%Y-%m-%d %H:%M:%S')", 23 | "end_time": "", 24 | "details": { 25 | "skipped_repos": [], 26 | "success_repos": [], 27 | "failed_repos": [] 28 | } 29 | } 30 | EOF 31 | } 32 | 33 | # 更新统计信息 34 | update_stats() { 35 | local key="$1" 36 | local value="$2" 37 | local type="$3" # 可以是 number 或 array 38 | 39 | if [ "$type" = "array" ]; then 40 | # 添加到数组 41 | jq --arg value "$value" \ 42 | ".details.$key += [\$value]" "$STATS_FILE" > "$STATS_FILE.tmp" 43 | else 44 | # 更新数值 45 | jq --arg key "$key" --argjson value "$value" \ 46 | ".$key = \$value" "$STATS_FILE" > "$STATS_FILE.tmp" 47 | fi 48 | mv "$STATS_FILE.tmp" "$STATS_FILE" 49 | } 50 | 51 | # 同步单个仓库 52 | sync_repository() { 53 | local repo="$1" 54 | local success=true 55 | 56 | # 检查 Gitea 仓库是否存在 57 | if ! curl -s -o /dev/null -f -H "Authorization: token $GITEA_TOKEN" \ 58 | "$GITEA_URL/api/v1/repos/$GITEA_USER/$repo"; then 59 | echo "在 Gitea 上创建仓库 $repo" 60 | if ! curl -X POST -H "Authorization: token $GITEA_TOKEN" \ 61 | -H "Content-Type: application/json" \ 62 | -d "{\"name\":\"$repo\",\"private\":false}" \ 63 | "$GITEA_URL/api/v1/user/repos"; then 64 | success=false 65 | fi 66 | fi 67 | 68 | # 克隆和推送 69 | [ -d "$repo" ] && rm -rf "$repo" 70 | if ! git clone --mirror "https://${GITHUB_TOKEN:+$GITHUB_TOKEN@}github.com/$GITHUB_USER/$repo.git" "$repo"; then 71 | success=false 72 | else 73 | cd "$repo" 74 | 75 | # 尝试 mirror 推送 76 | if ! git push --mirror "https://$GITEA_USER:$GITEA_TOKEN@${GITEA_URL#https://}/$GITEA_USER/$repo.git"; then 77 | echo "mirror 推送失败,尝试逐个分支推送..." 78 | 79 | # 获取所有分支 80 | git fetch --all 81 | 82 | # 推送每个分支 83 | git for-each-ref --format='%(refname:short)' refs/heads/ | while read branch; do 84 | echo "推送分支: $branch" 85 | if ! git push "https://$GITEA_USER:$GITEA_TOKEN@${GITEA_URL#https://}/$GITEA_USER/$repo.git" "$branch:$branch"; then 86 | success=false 87 | fi 88 | done 89 | 90 | # 推送所有标签 91 | if ! git push "https://$GITEA_USER:$GITEA_TOKEN@${GITEA_URL#https://}/$GITEA_USER/$repo.git" --tags; then 92 | success=false 93 | fi 94 | fi 95 | cd .. 96 | fi 97 | 98 | # 更新统计 99 | if [ "$success" = true ]; then 100 | update_stats "success" "$(( $(jq '.success' "$STATS_FILE") + 1 ))" "number" 101 | update_stats "success_repos" "$repo" "array" 102 | else 103 | update_stats "failed" "$(( $(jq '.failed' "$STATS_FILE") + 1 ))" "number" 104 | update_stats "failed_repos" "$repo" "array" 105 | fi 106 | } 107 | 108 | # 主同步逻辑 109 | main() { 110 | mkdir -p "$WORK_DIR" 111 | cd "$WORK_DIR" 112 | 113 | # 初始化统计 114 | init_stats 115 | 116 | # 获取仓库列表 117 | repos=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ 118 | "https://api.github.com/user/repos?per_page=100&type=all" | \ 119 | jq -r '.[].name') 120 | 121 | # 更新总仓库数 122 | total_repos=$(echo "$repos" | wc -l) 123 | update_stats "total_repos" "$total_repos" "number" 124 | 125 | # 同步每个仓库 126 | for repo in $repos; do 127 | # 检查是否跳过 128 | if echo "$SKIP_REPOS" | grep -q "$repo"; then 129 | echo "跳过仓库: $repo" 130 | update_stats "skipped" "$(( $(jq '.skipped' "$STATS_FILE") + 1 ))" "number" 131 | update_stats "skipped_repos" "$repo" "array" 132 | continue 133 | fi 134 | 135 | echo "处理仓库: $repo" 136 | update_stats "processed" "$(( $(jq '.processed' "$STATS_FILE") + 1 ))" "number" 137 | sync_repository "$repo" 138 | done 139 | 140 | # 更新结束时间 141 | jq --arg time "$(date '+%Y-%m-%d %H:%M:%S')" \ 142 | '.end_time = $time' "$STATS_FILE" > "$STATS_FILE.tmp" 143 | mv "$STATS_FILE.tmp" "$STATS_FILE" 144 | } 145 | 146 | main "$@" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GitHub to Gitea Mirror Script 2 | 3 | 这是一个自动将 GitHub 仓库镜像到 Gitea 的 Shell 脚本。支持批量同步所有仓库,可以设置跳过特定仓库,并具有良好的错误处理机制。 4 | 5 | ## 功能特性 6 | 7 | - 自动同步 GitHub 所有仓库到 Gitea 8 | - 支持设置跳过特定仓库 9 | - 分级推送策略(先尝试 mirror,失败后逐个推送分支) 10 | - 详细的进度显示和错误提示 11 | - 支持通过环境变量配置 12 | - 适合配合 crontab 使用 13 | - 支持运行后收集报告并发送邮件 14 | 15 | ## 必要条件 16 | 17 | - Git 18 | - curl 19 | - jq 20 | - GitHub Token(如需访问私有仓库) 21 | - Gitea Token 22 | 23 | ## 环境变量 24 | 25 | | 变量名 | 必需 | 说明 | 示例 | 26 | |--------|------|------|------| 27 | | GITHUB_USER | 是 | GitHub 用户名 | `songtianlun` | 28 | | GITHUB_TOKEN | 否 | GitHub 访问令牌 | `ghp_xxxxxxxxxxxx` | 29 | | GITEA_URL | 是 | Gitea 实例地址 | `https://git.example.com` | 30 | | GITEA_USER | 是 | Gitea 用户名 | `username` | 31 | | GITEA_TOKEN | 是 | Gitea 访问令牌 | `d4209xxxxxxxxxxxxx` | 32 | | SKIP_REPOS | 否 | 跳过的仓库列表(逗号分隔) | `repo1,repo2,repo3` | 33 | | WORK_DIR | 否 | 临时工作目录 | `/tmp/git-mirror` | 34 | | ENABLE_MAIL | 否 | 是否启用邮件通知 | `true` 或 `false` | `false` | 35 | | SMTP_SERVER | 否 | SMTP 服务器地址 | `smtp.gmail.com` | - | 36 | | SMTP_PORT | 否 | SMTP 端口 | `587` | `587` | 37 | | SMTP_USER | 否 | SMTP 用户名 | `your-email@gmail.com` | - | 38 | | SMTP_PASS | 否 | SMTP 密码 | `your-password` | - | 39 | | MAIL_TO | 否 | 接收通知的邮箱 | `your-email@example.com` | - | 40 | | MAIL_FROM | 否 | 发件人地址 | `noreply@example.com` | `$SMTP_USER` | 41 | 42 | ## 日志文件 43 | 44 | 脚本会自动创建日志文件,包含完整的运行记录: 45 | 46 | - 默认日志目录:`/tmp/github-mirror-logs` 47 | - 日志文件名格式:`mirror-YYYYMMDD-HHMMSS.log` 48 | - 每次运行创建新的日志文件 49 | 50 | ## 使用方法 51 | 52 | ### 直接运行 53 | 54 | ```bash 55 | GITHUB_USER=username \ 56 | GITHUB_TOKEN=your-github-token \ 57 | GITEA_URL=https://git.example.com \ 58 | GITEA_USER=username \ 59 | GITEA_TOKEN=your-gitea-token \ 60 | bash main.sh 61 | ``` 62 | 63 | ### 配置环境变量后运行 64 | 65 | ```bash 66 | # 设置环境变量 67 | export GITHUB_USER=username 68 | export GITHUB_TOKEN=your-github-token 69 | export GITEA_URL=https://git.example.com 70 | export GITEA_USER=username 71 | export GITEA_TOKEN=your-gitea-token 72 | 73 | # 运行脚本 74 | bash main.sh 75 | ``` 76 | 77 | ### 设置定时任务 78 | 79 | 编辑 crontab: 80 | ```bash 81 | crontab -e 82 | ``` 83 | 84 | 添加定时任务(每天凌晨 2 点运行): 85 | ```cron 86 | 0 2 * * * GITHUB_USER=username GITHUB_TOKEN=xxx GITEA_URL=https://git.example.com GITEA_USER=username GITEA_TOKEN=xxx /path/to/main.sh >> /path/to/main.log 2>&1 87 | ``` 88 | 89 | ### 跳过特定仓库 90 | 91 | ```bash 92 | GITHUB_USER=username \ 93 | GITEA_URL=https://git.example.com \ 94 | GITEA_USER=username \ 95 | GITEA_TOKEN=xxx \ 96 | SKIP_REPOS="repo1,repo2,repo3" \ 97 | bash main.sh 98 | ``` 99 | 100 | ## 邮件通知配置 101 | 102 | 脚本支持在运行完成后发送邮件通知,需要配置以下环境变量: 103 | 104 | | 变量名 | 必需 | 说明 | 示例 | 105 | |--------|------|------|------| 106 | | SMTP_SERVER | 否 | SMTP 服务器地址 | `smtp.gmail.com` | 107 | | SMTP_PORT | 否 | SMTP 端口 | `587` | 108 | | SMTP_USER | 否 | SMTP 用户名 | `your-email@gmail.com` | 109 | | SMTP_PASS | 否 | SMTP 密码 | `your-password` | 110 | | MAIL_TO | 否 | 接收通知的邮箱 | `your-email@example.com` | 111 | | MAIL_FROM | 否 | 发件人地址(默认为 SMTP_USER) | `noreply@example.com` | 112 | 113 | ### 邮件通知使用示例 114 | 115 | ### 完整配置示例 116 | ```bash 117 | GITHUB_USER=username \ 118 | GITHUB_TOKEN=xxx \ 119 | GITEA_URL=https://git.example.com \ 120 | GITEA_USER=username \ 121 | GITEA_TOKEN=xxx \ 122 | SMTP_SERVER=smtp.gmail.com \ 123 | SMTP_PORT=587 \ 124 | SMTP_USER=your-email@gmail.com \ 125 | SMTP_PASS=your-password \ 126 | MAIL_TO=your-email@example.com \ 127 | bash main.sh 128 | ``` 129 | 130 | ### Crontab 配置示例 131 | ```bash 132 | 0 2 * * * GITHUB_USER=username GITHUB_TOKEN=xxx GITEA_URL=https://git.example.com GITEA_USER=username GITEA_TOKEN=xxx SMTP_SERVER=smtp.gmail.com SMTP_PORT=587 SMTP_USER=your-email@gmail.com SMTP_PASS=your-password MAIL_TO=your-email@example.com /path/to/main.sh 133 | ``` 134 | 135 | ## 常见问题 136 | 137 | 1. **获取 GitHub Token** 138 | - 访问 GitHub Settings -> Developer settings -> Personal access tokens 139 | - 创建新的 Token,至少需要 `repo` 权限 140 | 141 | 2. **获取 Gitea Token** 142 | - 访问 Gitea 设置 -> 应用 -> 创建新的令牌 143 | - 需要仓库的读写权限 144 | 145 | 4. **错误处理** 146 | - 检查令牌权限是否正确 147 | - 确保 Gitea 实例可访问 148 | - 验证用户名和 URL 是否正确 149 | 150 | 5. 调试模式 151 | 152 | 添加 `-x` 参数启用调试模式: 153 | ```bash 154 | bash -x main.sh 155 | ``` 156 | 157 | ## 注意事项 158 | 159 | - 建议使用专门的目录存放脚本和日志 160 | - 定期检查日志确保同步正常 161 | - 谨慎保管 Token,不要泄露 162 | - 建议先使用测试账号验证配置 163 | - 大型仓库同步可能需要较长时间 164 | 165 | ## License 166 | 167 | MIT License 168 | 169 | ## 贡献 170 | 171 | 欢迎提交 Issue 和 Pull Request! 172 | 173 | ## Star History 174 | 175 | [![Star History Chart](https://api.star-history.com/svg?repos=songtianlun/mirrorGit&type=Timeline)](https://www.star-history.com/#songtianlun/mirrorGit&Timeline) 176 | --------------------------------------------------------------------------------