如何用脚本迁移Git仓库?

wen 实用脚本 2

本文目录导读:

如何用脚本迁移Git仓库?

  1. 使用Git原生命令(最基础)
  2. 完整迁移脚本(推荐)
  3. Python脚本(更灵活)
  4. 批量迁移脚本
  5. 带进度显示的脚本
  6. 使用建议

我来介绍几种脚本迁移Git仓库的方法,从简单到复杂。

使用Git原生命令(最基础)

#!/bin/bash
# 迁移Git仓库到新地址
# 源仓库地址
OLD_REPO="git@old-server:project.git"
# 新仓库地址
NEW_REPO="git@new-server:project.git"
# 克隆裸仓库(包含所有分支和标签)
git clone --bare $OLD_REPO
cd project.git
# 添加新远程并推送所有内容
git remote add new-origin $NEW_REPO
# 推送所有分支和标签
git push --all new-origin
git push --tags new-origin
cd ..
rm -rf project.git

完整迁移脚本(推荐)

#!/bin/bash
# Git仓库迁移脚本
# 用法: ./git-migrate.sh old-repo-url new-repo-url
set -e
OLD_REPO="$1"
NEW_REPO="$2"
if [ -z "$OLD_REPO" ] || [ -z "$NEW_REPO" ]; then
    echo "用法: $0 <旧仓库URL> <新仓库URL>"
    exit 1
fi
# 获取仓库名
REPO_NAME=$(basename "$OLD_REPO" .git)
echo "正在迁移仓库: $REPO_NAME"
echo "源地址: $OLD_REPO"
echo "目标地址: $NEW_REPO"
# 步骤1: 克隆裸仓库
echo "步骤1: 克隆源仓库..."
git clone --bare $OLD_REPO
cd "$REPO_NAME.git"
# 步骤2: 显示仓库信息
echo "步骤2: 仓库信息:"
echo "  - 分支列表:"
git branch
echo "  - 标签列表:"
git tag
echo "  - 最后提交:"
git log -1 --format="%H %s"
# 步骤3: 添加新远程
echo "步骤3: 设置新远程仓库..."
git remote add new-origin $NEW_REPO
# 步骤4: 推送所有内容
echo "步骤4: 推送所有分支和标签..."
git push --all new-origin
git push --tags new-origin
# 步骤5: 清理
cd ..
echo "步骤5: 清理临时文件..."
rm -rf "$REPO_NAME.git"
echo "迁移完成!"

Python脚本(更灵活)

#!/usr/bin/env python3
# git_migrate.py
import os
import sys
import shutil
import subprocess
import json
from pathlib import Path
class GitMigrator:
    def __init__(self, old_url, new_url):
        self.old_url = old_url
        self.new_url = new_url
        self.repo_name = self._get_repo_name()
        self.temp_dir = Path.cwd() / f"{self.repo_name}_temp"
    def _get_repo_name(self):
        """从URL提取仓库名"""
        name = self.old_url.rstrip('/').split('/')[-1]
        return name.replace('.git', '')
    def _run_command(self, cmd, cwd=None):
        """运行命令并返回输出"""
        result = subprocess.run(
            cmd,
            shell=True,
            cwd=cwd or str(self.temp_dir),
            capture_output=True,
            text=True
        )
        if result.returncode != 0:
            print(f"命令失败: {cmd}")
            print(f"错误: {result.stderr}")
            sys.exit(1)
        return result.stdout.strip()
    def get_repo_info(self):
        """获取仓库信息"""
        os.chdir(str(self.temp_dir))
        info = {
            "branches": [],
            "tags": [],
            "last_commit": ""
        }
        try:
            # 获取分支列表
            branches = self._run_command("git branch -r")
            info["branches"] = [b.strip() for b in branches.split('\n') if b.strip()]
            # 获取标签列表
            tags = self._run_command("git tag")
            info["tags"] = [t.strip() for t in tags.split('\n') if t.strip()]
            # 获取最后提交
            info["last_commit"] = self._run_command("git log -1 --format='%H %s'")
        except:
            pass
        return info
    def migrate(self):
        """执行迁移"""
        print(f"开始迁移仓库: {self.repo_name}")
        print(f"源: {self.old_url}")
        print(f"目标: {self.new_url}")
        try:
            # 步骤1: 克隆裸仓库
            print("\n[1/4] 克隆源仓库...")
            cmd = f"git clone --bare {self.old_url} {self.temp_dir.name}"
            self._run_command(cmd, cwd=Path.cwd())
            # 步骤2: 获取仓库信息
            print("\n[2/4] 获取仓库信息...")
            info = self.get_repo_info()
            print(f"  分支数量: {len(info['branches'])}")
            print(f"  标签数量: {len(info['tags'])}")
            print(f"  最后提交: {info['last_commit']}")
            # 步骤3: 设置新远程并推送
            print("\n[3/4] 推送至新仓库...")
            self._run_command(f"git remote add new-origin {self.new_url}")
            self._run_command("git push --all new-origin")
            self._run_command("git push --tags new-origin")
            print("\n[4/4] 清理临时文件...")
            os.chdir(str(Path.cwd()))
            shutil.rmtree(str(self.temp_dir))
            print(f"\n✅ 迁移成功!")
            return True
        except Exception as e:
            print(f"\n❌ 迁移失败: {e}")
            # 清理
            if self.temp_dir.exists():
                shutil.rmtree(str(self.temp_dir))
            return False
def main():
    if len(sys.argv) != 3:
        print("用法: python git_migrate.py <旧仓库URL> <新仓库URL>")
        print("示例: python git_migrate.py git@old.com:project.git git@new.com:project.git")
        sys.exit(1)
    migrator = GitMigrator(sys.argv[1], sys.argv[2])
    migrator.migrate()
if __name__ == "__main__":
    main()

批量迁移脚本

#!/bin/bash
# batch-git-migrate.sh - 批量迁移多个Git仓库
# 配置文件:每行格式 "旧URL 新URL"
CONFIG_FILE="repos.txt"
# 迁移列表文件示例内容:
# git@old-server:project1.git  git@new-server:project1.git
# git@old-server:project2.git  git@new-server:project2.git
# git@old-server:project3.git  git@new-server:project3.git
log_file="migration_$(date +%Y%m%d_%H%M%S).log"
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$log_file"
}
migrate_repo() {
    local old_url="$1"
    local new_url="$2"
    local repo_name=$(basename "$old_url" .git)
    log "开始迁移: $repo_name"
    # 克隆裸仓库
    if ! git clone --bare "$old_url" "/tmp/$repo_name.git" 2>> "$log_file"; then
        log "  ❌ 克隆失败: $repo_name"
        return 1
    fi
    cd "/tmp/$repo_name.git"
    # 添加新远程并推送
    if ! git remote add new-origin "$new_url" 2>> "$log_file"; then
        log "  ❌ 添加远程失败: $repo_name"
        cd /
        rm -rf "/tmp/$repo_name.git"
        return 1
    fi
    # 推送所有内容
    if ! git push --all new-origin 2>> "$log_file" || ! git push --tags new-origin 2>> "$log_file"; then
        log "  ❌ 推送失败: $repo_name"
        cd /
        rm -rf "/tmp/$repo_name.git"
        return 1
    fi
    cd /
    rm -rf "/tmp/$repo_name.git"
    log "  ✅ 迁移成功: $repo_name"
    return 0
}
# 主流程
log "开始批量迁移Git仓库..."
log "配置文件: $CONFIG_FILE"
if [ ! -f "$CONFIG_FILE" ]; then
    log "❌ 配置文件不存在: $CONFIG_FILE"
    exit 1
fi
success=0
failed=0
total=0
while IFS=' ' read -r old_url new_url || [ -n "$old_url" ]; do
    # 跳过空行和注释
    [[ -z "$old_url" || "$old_url" =~ ^# ]] && continue
    total=$((total + 1))
    if migrate_repo "$old_url" "$new_url"; then
        success=$((success + 1))
    else
        failed=$((failed + 1))
    fi
done < "$CONFIG_FILE"
log "迁移完成!"
log "总计: $total, 成功: $success, 失败: $failed"
# 显示报告
echo ""
echo "========== 迁移报告 =========="
echo "总计仓库数: $total"
echo "成功迁移: $success"
echo "失败: $failed"
echo "日志文件: $log_file"
echo "=============================="

带进度显示的脚本

#!/bin/bash
# git-migrate-progress.sh
source_repo="$1"
target_repo="$2"
show_progress() {
    local current=$1
    local total=$2
    local width=50
    local percentage=$((current * 100 / total))
    local completed=$((width * current / total))
    printf "\r进度: ["
    for ((i=0; i<completed; i++)); do printf "#"; done
    for ((i=completed; i<width; i++)); do printf " "; done
    printf "] %d%%" $percentage
}
echo "===== Git仓库迁移工具 ====="
echo "源: $source_repo"
echo "目标: $target_repo"
echo ""
# 设置陷阱,确保清理
trap 'echo ""; echo "迁移中断,清理中..."; rm -rf /tmp/*.git 2>/dev/null; exit 1' INT TERM
# 步骤1: 克隆
echo "步骤1/3: 克隆源仓库..."
show_progress 1 3
git clone --bare "$source_repo" /tmp/migrate_temp.git 2>/dev/null
if [ $? -ne 0 ]; then
    echo ""
    echo "❌ 克隆失败"
    exit 1
fi
cd /tmp/migrate_temp.git || exit 1
# 步骤2: 添加远程
echo ""
echo "步骤2/3: 配置目标仓库..."
show_progress 2 3
git remote add new-origin "$target_repo" 2>/dev/null
# 步骤3: 推送
echo ""
echo "步骤3/3: 推送数据..."
show_progress 3 3
git push --all new-origin 2>/dev/null
git push --tags new-origin 2>/dev/null
# 清理
cd /
rm -rf /tmp/migrate_temp.git
echo ""
echo ""
echo "✅ 迁移完成!"

使用建议

  1. 权限检查:确保有源仓库的读取权限和目标仓库的写入权限
  2. 网络测试:大仓库迁移前先测试网络连接
  3. 增量迁移:对于大型仓库,考虑分批迁移
  4. 验证:迁移后在新仓库验证所有分支和标签
  5. 备份:重要仓库迁移前先在源端创建备份

执行示例

# 基本迁移
chmod +x git-migrate.sh
./git-migrate.sh git@old-server:project.git git@new-server:project.git
# Python版本
python3 git_migrate.py git@old-server:project.git git@new-server:project.git
# 批量迁移
./batch-git-migrate.sh

选择哪种脚本取决于你的具体需求,推荐使用第2个完整性较高的Shell脚本。

抱歉,评论功能暂时关闭!