Git 仓库批量迁移

家里电脑上积累了很多 Git 项目,自从搭建了 Gitea 后,一直想把这些项目迁移过去。但是几十个项目,挨个迁移实在太麻烦了,所以一直拖着。

上篇文章写了git镜像推送的命令,正好趁热打铁,写个脚本来批量迁移这些仓库。

核心思路

  1. 遍历目标目录下的每个子目录。
  2. 判断它是不是 Git 仓库。
  3. 先拉取原远程的最新分支和标签。
  4. 调用 Gitea API 创建同名私有仓库。
  5. 临时添加一个新的 Gitea 远程。
  6. 执行 git push --mirror 全量推送。
  7. 推送完成后移除临时远程。

完整迁移脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#!/bin/bash

set -euo pipefail

#======================= 配置区域 =======================
# 待遍历的目录(绝对路径,末尾不要带 /)
TARGET_DIR="/path/to/repos"

# Gitea 基础 URL
GITEA_URL="https://gitea.example.com"

# Gitea 目标组织名
GITEA_ORG="your-org"

# Gitea Token,需要有创建仓库权限
GITEA_TOKEN="your-token"

# Gitea 仓库 SSH 前缀
GITEA_REPO_PREFIX="ssh://git@gitea.example.com:2222"

# 原仓库远程名
ORIGIN_REMOTE="origin"
#=======================================================

cd "$TARGET_DIR" || {
echo "错误: 无法进入目录 $TARGET_DIR"
exit 1
}

echo "工作目录: $TARGET_DIR"
echo "Gitea 组织: $GITEA_ORG"
echo "拉取远程: $ORIGIN_REMOTE"
echo "=============================="

for dir in */; do
[ -d "$dir" ] || continue

REPO_NAME=$(basename "$dir")
echo "处理仓库: $REPO_NAME"

if [ ! -d "$dir/.git" ]; then
echo " 跳过: 不是 Git 仓库"
continue
fi

pushd "$dir" > /dev/null || {
echo " 错误: 无法进入 $dir"
continue
}

echo " 清理本地更改..."
git reset --hard HEAD 2>/dev/null || true
git clean -fdx 2>/dev/null || true

if git remote get-url "$ORIGIN_REMOTE" >/dev/null 2>&1; then
echo " 正在从 $ORIGIN_REMOTE 拉取全量数据..."
if ! git fetch "$ORIGIN_REMOTE" --prune --tags --force; then
echo " 警告: 拉取失败,将只推送本地已有内容"
fi
else
echo " 警告: 未找到远程 '$ORIGIN_REMOTE',跳过拉取"
fi

echo " 在 Gitea 组织 $GITEA_ORG 创建/检查仓库 $REPO_NAME ..."
CREATE_RESPONSE=$(curl -s -w "%{http_code}" -o /dev/null \
-X POST \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"name\":\"$REPO_NAME\",\"private\":true}" \
"${GITEA_URL}/api/v1/orgs/${GITEA_ORG}/repos")

if [ "$CREATE_RESPONSE" = "201" ]; then
echo " 仓库创建成功 (私有)"
elif [ "$CREATE_RESPONSE" = "409" ]; then
echo " 仓库已存在,将直接推送"
else
echo " 警告: 创建仓库失败,HTTP 状态码 $CREATE_RESPONSE,将继续尝试推送"
fi

NEW_REMOTE_URL="${GITEA_REPO_PREFIX}/${GITEA_ORG}/${REPO_NAME}.git"

echo " 添加临时远程 'gitea' ..."
git remote remove gitea 2>/dev/null || true
git remote add gitea "$NEW_REMOTE_URL"

echo " 全量推送至新仓库..."
if git push --mirror gitea; then
echo " 推送成功"
else
echo " 错误: 推送失败,请检查权限或仓库状态"
fi

git remote remove gitea
echo " 临时远程 'gitea' 已移除"

popd > /dev/null
echo ""
done

echo "全部处理完成。"

使用方式

先把脚本保存成一个文件,比如 migrate.sh,然后给执行权限:

1
chmod +x migrate.sh

执行:

1
./migrate.sh

如果你的 Gitea 使用的是 SSH 推送,记得提前把本机公钥加到 Gitea 账号里;否则脚本能创建仓库,但推送会失败。