fix: сравнение с origin через merge-base (расхождение веток)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -117,17 +117,57 @@ async function gitCmd(args, cwd, { needsWrite = false } = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
/** Сколько коммитов на origin/main без записи в .git (без fetch) */
|
||||
async function getCommitsBehind(root) {
|
||||
/**
|
||||
* Сравнение с origin/main через ls-remote + merge-base (без fetch, без записи в .git).
|
||||
*/
|
||||
async function getRemoteSyncStatus(root) {
|
||||
const localHead = (await gitCmd(['rev-parse', 'HEAD'], root)).split('\n')[0].trim();
|
||||
const remoteOut = await gitCmd(['ls-remote', 'origin', 'refs/heads/main'], root);
|
||||
const remoteSha = remoteOut.split(/\s+/)[0]?.trim();
|
||||
if (!remoteSha) {
|
||||
throw new Error('Не найден refs/heads/main на origin');
|
||||
}
|
||||
if (remoteSha === localHead) return 0;
|
||||
const count = await gitCmd(['rev-list', '--count', `${localHead}..${remoteSha}`], root);
|
||||
return parseInt(count, 10) || 0;
|
||||
|
||||
const remoteShort = (
|
||||
await gitCmd(['rev-parse', '--short', remoteSha], root)
|
||||
).split('\n')[0].trim();
|
||||
|
||||
if (remoteSha === localHead) {
|
||||
return { behind: 0, ahead: 0, diverged: false, remoteShort, remoteSha };
|
||||
}
|
||||
|
||||
let mergeBase;
|
||||
try {
|
||||
mergeBase = (await gitCmd(['merge-base', localHead, remoteSha], root)).split('\n')[0].trim();
|
||||
} catch {
|
||||
throw new Error(
|
||||
'Не удалось сравнить с origin/main (нет общего предка). Выполните на сервере: git fetch && git reset --hard origin/main'
|
||||
);
|
||||
}
|
||||
|
||||
if (!mergeBase) {
|
||||
throw new Error('Нет общего предка с origin/main');
|
||||
}
|
||||
|
||||
let behind = 0;
|
||||
let ahead = 0;
|
||||
|
||||
if (mergeBase !== remoteSha) {
|
||||
const behindStr = await gitCmd(['rev-list', '--count', `${mergeBase}..${remoteSha}`], root);
|
||||
behind = parseInt(behindStr, 10) || 0;
|
||||
}
|
||||
if (mergeBase !== localHead) {
|
||||
const aheadStr = await gitCmd(['rev-list', '--count', `${mergeBase}..${localHead}`], root);
|
||||
ahead = parseInt(aheadStr, 10) || 0;
|
||||
}
|
||||
|
||||
return {
|
||||
behind,
|
||||
ahead,
|
||||
diverged: behind > 0 && ahead > 0,
|
||||
remoteShort,
|
||||
remoteSha,
|
||||
};
|
||||
}
|
||||
|
||||
async function getGitInfo({ fetchRemote = false } = {}) {
|
||||
@@ -157,6 +197,9 @@ async function getGitInfo({ fetchRemote = false } = {}) {
|
||||
dirty: false,
|
||||
dirtyHint: null,
|
||||
behind: null,
|
||||
ahead: null,
|
||||
diverged: false,
|
||||
remoteShort: null,
|
||||
updateEnabled: isUpdateEnabled(),
|
||||
platform: process.platform,
|
||||
};
|
||||
@@ -191,7 +234,11 @@ async function getGitInfo({ fetchRemote = false } = {}) {
|
||||
|
||||
if (fetchRemote) {
|
||||
try {
|
||||
info.behind = await getCommitsBehind(root);
|
||||
const sync = await getRemoteSyncStatus(root);
|
||||
info.behind = sync.behind;
|
||||
info.ahead = sync.ahead;
|
||||
info.diverged = sync.diverged;
|
||||
info.remoteShort = sync.remoteShort;
|
||||
} catch (err) {
|
||||
info.fetchError = err.message;
|
||||
if (repoOwner) {
|
||||
|
||||
Reference in New Issue
Block a user