GitLab 到 GitHub 批量项目迁移指南

目标:

使用nodejs程序将 GitLab 中的多个项目批量迁移到 GitHub 上。该过程包括以下步骤:

  1. 获取 GitLab 中的项目列表。
  2. 在 GitHub 上创建对应的私有仓库。
  3. 克隆 GitLab 上的项目到本地。
  4. 将项目推送到 GitHub。
  5. 如果迁移失败,删除已在步骤2创建的GitHub的仓库。

关键步骤:

1. 获取 GitLab 项目列表

使用 GitLab API 获取所有项目的列表。通过提供的访问令牌(Private Token)进行身份验证。

2. 创建 GitHub 仓库

使用 GitHub API 在目标账户下创建私有仓库,仓库名与 GitLab 仓库一致。

3. 克隆 GitLab 项目

使用 simple-git 库克隆 GitLab 上的项目到本地。每个项目会被克隆到一个单独的子目录中,确保项目不会相互覆盖。

4. 推送到 GitHub

在本地仓库中进行必要的提交操作,然后将项目推送到新创建的 GitHub 仓库。
使用 SSH URL 推送代码,确保代码的安全性。

5. 错误处理与回滚

如果推送失败,删除 GitHub 上创建的仓库,并跳过该项目继续执行迁移。

全部代码

1. 配置文件(config.js

存储 GitLab 和 GitHub 的 API 访问令牌。

module.exports = {
  gitlabAccessToken: 'your_gitlab_access_token',// 自己填写
  githubAccessToken: 'your_github_access_token',// 自己填写
  gitlabUrl: 'https://gitlab.com/api/v4/projects',// 如果是本地搭建的服务,请把https://gitlab.com替换成你自己的地址
  githubUserName: 'your_github_user_name',// 自己填写
  githubUrl: 'https://api.github.com/user/repos'// 不用修改
};

2. 主逻辑(trans.js

const fs = require('fs');
const path = require('path');
const axios = require('axios');
const simpleGit = require('simple-git');

// 引入配置
const config = require('./config');

// GitLab 和 GitHub 配置信息
const gitlabAccessToken = config.gitlabAccessToken;
const githubAccessToken = config.githubAccessToken;
const gitlabUrl = config.gitlabUrl;
const githubUserName = config.githubUserName;
const githubUrl = config.githubUrl;

// 设置请求头
const gitlabHeaders = {
  'PRIVATE-TOKEN': gitlabAccessToken
};

const githubHeaders = {
  'Authorization': `token ${githubAccessToken}`,
  'Accept': 'application/vnd.github.v3+json'
};

// 创建一个 simple-git 实例
const git = simpleGit();

// 获取 GitLab 项目列表
async function getGitLabProjects() {
  try {
    const response = await axios.get(gitlabUrl, { headers: gitlabHeaders });
    return response.data;
  } catch (error) {
    console.error('Error fetching GitLab projects:', error.message);
    return [];
  }
}

// 在 GitHub 上创建仓库
async function createGitHubRepo(repoName) {
  try {
    const response = await axios.post(
      githubUrl,
      { name: repoName, private: true },
      { headers: githubHeaders }
    );
    console.log(`Successfully created GitHub repository: ${repoName}`);
    return response.data;
  } catch (error) {
    if (error.response) {
      console.error(`Error creating GitHub repository[${repoName}]:`, error.response.data.errors.map(e => e.message).join(','));
    } else {
      console.error('Error:', error.message);
    }
    return null;
  }
}

// 删除 GitHub 仓库
async function deleteGitHubRepo(repoName) {
  try {
    const response = await axios.delete(
      `https://api.github.com/repos/${githubUserName}/${repoName}`,
      { headers: githubHeaders }
    );
    console.log(`Successfully deleted GitHub repository: ${repoName}`);
    return true;
  } catch (error) {
    if (error.response) {
      console.error('Error deleting GitHub repository:', error.response.data);
    } else {
      console.error('Error:', error.message);
    }
    return false;
  }
}

// 删除已存在的目录
function deleteDirectory(dirPath) {
  if (fs.existsSync(dirPath)) {
    fs.rmdirSync(dirPath, { recursive: true }); // 删除目录及其内容
    console.log(`Deleted existing directory: ${dirPath}`);
  }
}

// 克隆 GitLab 仓库并推送到 GitHub
async function migrateRepo(gitlabRepoUrl, githubRepoUrl, repoName) {
  try {
    const cloneDir = path.join(__dirname, 'projects', repoName);  // 所有项目放在 'projects' 文件夹下

    // 删除已存在的目标目录
    deleteDirectory(cloneDir);

    // 克隆仓库
    console.log(`Cloning ${gitlabRepoUrl} into ${cloneDir}...`);
    await git.clone(gitlabRepoUrl, cloneDir);  // 克隆到独立的目录
    await git.cwd(cloneDir);  // 进入该目录

    // 获取当前分支(可能是 main 或 master)
    const branches = await git.branch();
    let defaultBranch = branches.all.includes('main') ? 'main' : 'master';

    // 确保至少有一个提交
    const status = await git.status();
    if (status.files.length > 0 || status.isClean === false) {
      // 将所有文件添加到 Git
      await git.add('.');  // 添加所有文件
      await git.commit('Initial commit');  // 提交文件
    } else {
      console.log('No changes to commit.');
    }

    // 添加 GitHub 远程仓库
    await git.addRemote('github', githubRepoUrl);

    // 推送代码到 GitHub
    console.log(`Pushing to GitHub repository: ${githubRepoUrl}`);
    await git.push('github', defaultBranch); // 推送到 main 或 master
    console.log('Repository successfully migrated to GitHub.');
  } catch (error) {
    console.error('Error migrating repository:', error.message);

    // 如果推送失败,则删除 GitHub 仓库
    console.log('Attempting to delete the repository on GitHub...');
    await deleteGitHubRepo(repoName);
  }
}

// 主流程
async function migrateAllProjects() {
  const gitlabProjects = await getGitLabProjects();

  // 确保 'projects' 目录存在
  const projectsDir = path.join(__dirname, 'projects');
  if (!fs.existsSync(projectsDir)) {
    fs.mkdirSync(projectsDir);  // 如果 'projects' 目录不存在,则创建
    console.log(`Created directory: ${projectsDir}`);
  }

  for (let project of gitlabProjects) {
    const gitlabRepoUrl = project.http_url_to_repo;
    const repoName = project.name;

    // 创建 GitHub 仓库
    const githubRepo = await createGitHubRepo(repoName);
    if (!githubRepo) {
      continue;  // 如果 GitHub 仓库创建失败,则跳过
    }

    const githubRepoUrl = githubRepo.ssh_url;  // 获取 SSH URL

    // 将项目从 GitLab 克隆到 GitHub
    await migrateRepo(gitlabRepoUrl, githubRepoUrl, repoName);
  }
}

// 执行迁移
migrateAllProjects().catch(console.error);

运行步骤

1. 安装依赖

使用以下命令安装所需的 npm 包:

 npm install axios simple-git

2. 配置环境

创建 config.js 文件,并将 GitLab 和 GitHub 的 API 令牌填入其中

3.运行脚本进行迁移

node trans.js
执行结果
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容