目标:
使用nodejs程序将 GitLab 中的多个项目批量迁移到 GitHub 上。该过程包括以下步骤:
- 获取 GitLab 中的项目列表。
- 在 GitHub 上创建对应的私有仓库。
- 克隆 GitLab 上的项目到本地。
- 将项目推送到 GitHub。
- 如果迁移失败,删除已在步骤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
执行结果