You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord.js机器人多GitHub仓库同步更新实现问题求助

Discord.js机器人多GitHub仓库同步更新实现问题求助

我刚接触GitHub,最近在给我的Discord.js机器人开发一套多仓库同步更新的系统,目前规划了三个仓库来实现不同的功能:

  • authCodeRepoUrl:存放机器人的核心业务代码(比如命令、事件逻辑等),这个仓库需要每次都拉取最新的远程代码覆盖本地
  • authDataRepoUrl:专门存储机器人的.json数据文件,需要对比本地和远程文件的更新时间,实现双向同步(哪边文件更新就以哪边为准同步)
  • authBackupRepoUrl:用来备份机器人的整个运行文件夹,这样我在任意设备都能查看完整的文件状态

我自己尝试写了实现代码,遇到问题后找AI帮忙调试,但不确定是不是真的解决了问题,所以来这里求助各位大佬(提前说声抱歉)。

我的实现代码如下:

const { exec } = require('child_process');
const path = require('path');
const fs = require('fs');
require('dotenv').config();
const os = require('os');
const codeRepoUrl = process.env.CODE_REPO_URL;
const dataRepoUrl = process.env.DATA_REPO_URL;
const backupRepoUrl = process.env.BACKUP_REPO_URL;
const token = process.env.GITHUB_PAT;
const allowedHost = 'ncpi';
const currentHost = os.hostname();

if (!codeRepoUrl || !dataRepoUrl || !backupRepoUrl || !token) {
    console.error('[ERROR] CODE_REPO_URL, DATA_REPO_URL, BACKUP_REPO_URL, or GITHUB_PAT is not set in .env');
    process.exit(1);
}

const codeRepoPath = path.join(__dirname, './');
const dataRepoPath = path.join(__dirname, 'Data');
const logFilePath = path.join(dataRepoPath, 'sync_log.txt');

const authCodeRepoUrl = codeRepoUrl.replace('https://', `https://${token}@`);
const authDataRepoUrl = dataRepoUrl.replace('https://', `https://${token}@`);
const authBackupRepoUrl = backupRepoUrl.replace('https://', `https://${token}@`);

// Git操作辅助函数
function execPromise(command) {
    return new Promise((resolve, reject) => {
        exec(command, (error, stdout, stderr) => {
            if (error) {
                reject(stderr || stdout);
            } else {
                resolve(stdout);
            }
        });
    });
}

async function getDefaultBranch(repoPath) {
    try {
        const branchName = await execPromise(`git -C ${repoPath} symbolic-ref --short HEAD`);
        return branchName.trim();
    } catch {
        return 'main';
    }
}

async function syncDataRepo() {
    try {
        console.log('[INFO] Syncing data repository...');
        if (!fs.existsSync(dataRepoPath)) {
            console.log('[INFO] Cloning data repository...');
            await execPromise(`git clone ${authDataRepoUrl} ${dataRepoPath}`);
        } else {
            console.log('[INFO] Pulling latest changes for the data repository...');
            await execPromise(`git -C ${dataRepoPath} pull`);
        }

        await execPromise(`git -C ${dataRepoPath} branch --set-upstream-to=origin/main main`);

        const localChanges = await execPromise(`git -C ${dataRepoPath} status --porcelain`);
        if (localChanges.trim().length > 0) {
            console.log('[INFO] Local changes detected. Pushing to remote repository...');
            await execPromise(
                `git -C ${dataRepoPath} add . && git -C ${dataRepoPath} commit -m "Auto-sync: ${new Date().toISOString()}" && git -C ${dataRepoPath} push`
            );
        }

        console.log('[INFO] Data repository synchronized.');
        logSyncSuccess();
    } catch (error) {
        console.error('[ERROR] Failed to synchronize data repository:', error);
    }
}


function logSyncSuccess() {
    const timestamp = `[SUCCESS] Data repository synchronized at: ${new Date().toISOString()}\n\n`;
    try {
        fs.appendFileSync(logFilePath, timestamp, 'utf8');
        console.log('[INFO] Sync timestamp logged.');
    } catch (err) {
        console.error('[ERROR] Failed to write sync log:', err);
    }
}

async function syncCodeRepo() {
    if (currentHost !== allowedHost) {
        console.log('[INFO] Code synchronization skipped: Not running on the allowed device.');
        return;
    }

    try {
        console.log('[INFO] Syncing code repository...');
        const branchName = await getDefaultBranch(codeRepoPath);

        if (!fs.existsSync(path.join(codeRepoPath, '.git'))) {
            console.log('[INFO] Cloning code repository...');
            await execPromise(`git clone ${authCodeRepoUrl} ${codeRepoPath}`);
        } else {
            console.log('[INFO] Pulling latest changes for the code repository...');
            try {
                await execPromise(`git -C ${codeRepoPath} remote add origin ${authCodeRepoUrl}`);
            } catch (error) {
                if (!error.includes('remote origin already exists')) {
                    throw error;
                }
            }
            await execPromise(`git -C ${codeRepoPath} pull origin ${branchName}`);
        }

        await execPromise(`git -C ${codeRepoPath} branch --set-upstream-to=origin/${branchName} ${branchName}`);

        console.log('[INFO] Code repository synchronized.');
    } catch (error) {
        console.error('[ERROR] Failed to synchronize code repository:', error);
    }
}


async function backupToRemoteRepo() {
    if (currentHost !== allowedHost) {
        console.log('[INFO] Backup skipped: Not running on the allowed device.');
        return;
    }

    try {
        console.log('[INFO] Backing up directly to remote repository...');
        const branchName = 'main';

        if (!fs.existsSync(path.join(codeRepoPath, '.git'))) {
            console.log('[INFO] Initializing repository for backup...');
            await execPromise(`git -C ${codeRepoPath} init`);
            await execPromise(`git -C ${codeRepoPath} checkout -b ${branchName}`);
            await execPromise(`git -C ${codeRepoPath} remote add origin ${authBackupRepoUrl}`);
        }

        await execPromise(`git -C ${codeRepoPath} config user.email "email censored"`);
        await execPromise(`git -C ${codeRepoPath} config user.name "github user censored"`);

        await execPromise(`git -C ${codeRepoPath} add .`);
        await execPromise(`git -C ${codeRepoPath} commit -m "Backup: ${new Date().toISOString()}"`);
        await execPromise(`git -C ${codeRepoPath} push origin ${branchName} --force`);

        console.log('[INFO] Backup to remote repository completed.');
    } catch (error) {
        console.error('[ERROR] Failed to backup to remote repository:', error);
    }
}


async function checkAndUpdate() {
    console.log('[INFO] Starting update process...');
    await syncCodeRepo();
    await syncDataRepo();
    await backupToRemoteRepo();
    console.log('[INFO] Update process completed.');
    scheduleNextSync();
}

function scheduleNextSync() {
    const now = new Date();
    const minutes = now.getMinutes();
    const nextInterval = 10 - (minutes % 10);
    const delay = nextInterval * 60 * 1000;

    console.log(`[INFO] Next sync scheduled in ${nextInterval} minutes (${new Date(now.getTime() + delay).toLocaleTimeString()}).`);

    setTimeout(() => {
        checkAndUpdate().then(scheduleRecurringSync);
    }, delay);
}

function scheduleRecurringSync() {
    console.log('[INFO] Scheduling recurring sync every 10 minutes.');
    setInterval(checkAndUpdate, 10 * 60 * 1000);
}

module.exports = { checkAndUpdate };

运行代码后出现了以下错误日志:

0| [ERROR] Failed to synchronize data repository: There is no tracking information for the current branch.
0| Please specify which branch you want to merge with.
0| See git-pull(1) for details.
0|     git pull <remote> <branch>
0| If you wish to set tracking information for this branch you can do so with:
0|     git branch --set-upstream-to=<remote>/<branch> master
0| [INFO] Backing up directly to remote repository...
0| [ERROR] Failed to backup to remote repository: error: src refspec main does not match any
0| error: failed to push some refs to 'https://github.com/censored/censored'
0| [INFO] Update process completed.
0| [INFO] Next sync scheduled in 10 minutes (04:10:37).
0| [INFO] Bot and data repositories are up-to-date. Starting bot...
0| [INFO] Starting update process...
0| [INFO] Syncing code repository...
0| [INFO] Pulling latest changes for the code repository...
0| [ERROR] Failed to synchronize code repository: fatal: couldn't find remote ref master
0| [INFO] Syncing data repository...
0| [INFO] Pulling latest changes for the data repository...
0| [ERROR] Failed to synchronize data repository: There is no tracking information for the current branch.
0| Please specify which branch you want to merge with.
0| See git-pull(1) for details.
0|     git pull <remote> <branch>
0| If you wish to set tracking information for this branch you can do so with:
0|     git branch --set-upstream-to=<remote>/<branch> master
0| [INFO] Backing up directly to remote repository...
0| [ERROR] Failed to backup to remote repository: On branch master
0| nothing to commit, working tree clean
0| [INFO] Update process completed.
0| [INFO] Next sync scheduled in 10 minutes (04:20:39).
0| [INFO] Scheduling recurring sync every 10 minutes.

真心希望能得到大家的帮助,我真的很想让这个同步系统正常运行,提前谢谢各位了!

备注:内容来源于stack exchange,提问作者Blaxyy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 13:24:30