git 代码备份

// 将指定目录下的所有 git 项目,备份至一个 git 仓库中
// gitea 有 api 可以批量建库

using System.Collections.Concurrent;
using CliWrap;
using CliWrap.Buffered;

// 列出所有待操作的目录 
var root = "D:\\xCodes\\";
var folders = Directory.EnumerateDirectories(root, "*", SearchOption.AllDirectories);

foreach (var folder in folders)
{
    // 处理有 .git 的目录 
    var gitfolder = Path.Combine(folder, ".git");
    if (!Directory.Exists(gitfolder))
    {
        continue;
    }

    // 有 xignore 文件或目录的直接跳过
    var xignoreFile = Path.Combine(folder, "xignore");
    if (File.Exists(xignoreFile) || Directory.Exists(xignoreFile))
    {
        Console.WriteLine($"{folder} has xignore file or directory");
        continue;
    }

    // 待处理目录 
    Console.WriteLine(folder);

    var folderName = Path.GetFileName(folder);

    //  检测有没有未签入的数据, 如果有的话,人工核对处理
    var result = await Cli.Wrap("git")
        .WithArguments(["status", "--porcelain"])
        .WithWorkingDirectory(folder)
        .ExecuteBufferedAsync();

    if (result.ExitCode != 0)
    {
        throw new Exception($"git remote failed: {result.ExitCode}");
    }

    if (!string.IsNullOrWhiteSpace(result.StandardOutput))
    {
        throw new Exception($"git status not clean: {folder},  {result.StandardOutput}");
    }

    // 列出所有远程 
    result = await Cli.Wrap("git")
        .WithArguments(["remote"])
        .WithWorkingDirectory(folder)
        .ExecuteBufferedAsync();

    if (result.ExitCode != 0)
    {
        throw new Exception($"git remote failed: {result.ExitCode}");
    }

    var remotes = result.StandardOutput.Split('\r', '\n').Where(x => !string.IsNullOrWhiteSpace(x)).ToArray();

    // 为了方便,统一将备份远程命名为 x_backup
    if (!remotes.Contains("x_backup"))
    {
        // 如果没有,新建远程 
        var remote = remotes.First();

        // 取一个现有的仓库名名作为现在使用的仓库名,如果出错,人工再修改
        result = await Cli.Wrap("git")
            .WithArguments(["remote", "get-url", remote])
            .WithWorkingDirectory(folder)
            .ExecuteBufferedAsync();

        if (result.ExitCode != 0)
        {
            throw new Exception($"git remote failed: {result.ExitCode}");
        }

        var uri = new Uri(result.StandardOutput);
        var fileName = Path.GetFileNameWithoutExtension(uri.LocalPath);

        Console.WriteLine($"{remote}: {fileName}");

        // 新建远程 
        var newUrl = $"https://git.xxx.xxx/x/{fileName}.git";
        Console.WriteLine(newUrl);

        result = await Cli.Wrap("git")
            .WithArguments(["remote", "add", "x_backup", newUrl])
            .WithWorkingDirectory(folder)
            .ExecuteBufferedAsync();

        if (result.ExitCode != 0)
        {
            throw new Exception($"git remote failed: {result.ExitCode}");
        }
    }

    // 将所有分支推送至远程 
    result = await Cli.Wrap("git")
        .WithArguments(["push", "--all", "x_backup"])
        .WithWorkingDirectory(folder)
        .ExecuteBufferedAsync();

    if (result.ExitCode != 0)
    { 
        throw new Exception($"git remote failed: {result.ExitCode}");        
    }
}
# gitea 操作

# 判断库是否存在
# /api/v1/repos/$giteaUsername/$targetRepoName 
$response = Invoke-RestMethod -Uri $apiUrl -Headers $headers -Method Get

# 从三方库导入
# /api/v1/repos/migrate
    # 构建请求体
    $body = @{
        clone_addr    = $remoteGitRepoUrl # 待导入库 地址 
        uid           = (Invoke-RestMethod -Uri "$env:GITEA_SERVER_URL/api/v1/users/$giteaUsername" -Headers @{Authorization = "token $env:GITEA_API_TOKEN" }).id # 应该是当前用户 id
        repo_name     = $targetRepoName # 库名
        mirror        = $false # 要不要自动从源 git 库中定时同步
        private       = $true # 是否设置为私有
        auth_username = $remoteGitUsername # 待导入库的账号
        auth_password = $remoteGitPassword # 待导入库的密码
    } | ConvertTo-Json

    # 发送 POST 请求
    $response = Invoke-RestMethod -Uri $apiUrl -Method Post -Headers @{Authorization = "token $env:GITEA_API_TOKEN" } -Body $body -ContentType "application/json"
上一篇
下一篇